From a7a32e6af1117e6e7e53c7df88ae929a443b7985 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Fri, 25 Apr 2025 07:46:45 +0200 Subject: [PATCH 1/7] Fix module_are_literals_compressed to perform an unaligned read Signed-off-by: Paul Guyot --- src/libAtomVM/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libAtomVM/module.c b/src/libAtomVM/module.c index 0cbdb6a77..73de8e1af 100644 --- a/src/libAtomVM/module.c +++ b/src/libAtomVM/module.c @@ -381,7 +381,7 @@ COLD_FUNC void module_destroy(Module *module) static bool module_are_literals_compressed(const uint8_t *litT) { - uint32_t required_buf_size = READ_32_ALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); + uint32_t required_buf_size = READ_32_UNALIGNED(litT + LITT_UNCOMPRESSED_SIZE_OFFSET); return (required_buf_size != 0); } From c09850a443a020b2599cf627a2f2cc22a187affe Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Mon, 17 Mar 2025 22:57:59 +0100 Subject: [PATCH 2/7] Use size_t for atom_table_count Signed-off-by: Paul Guyot --- src/libAtomVM/atom_table.c | 10 +++++----- src/libAtomVM/atom_table.h | 2 +- src/libAtomVM/opcodesswitch.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libAtomVM/atom_table.c b/src/libAtomVM/atom_table.c index af474aa3b..d91cacf70 100644 --- a/src/libAtomVM/atom_table.c +++ b/src/libAtomVM/atom_table.c @@ -64,8 +64,8 @@ struct HNodeGroup struct AtomTable { - int capacity; - int count; + size_t capacity; + size_t count; int last_node_group_avail; #ifndef AVM_NO_SMP RWLock *lock; @@ -118,10 +118,10 @@ void atom_table_destroy(struct AtomTable *table) free(table); } -int atom_table_count(struct AtomTable *table) +size_t atom_table_count(struct AtomTable *table) { SMP_RDLOCK(table); - int count = table->count; + size_t count = table->count; SMP_UNLOCK(table); return count; @@ -204,7 +204,7 @@ long atom_table_get_index(struct AtomTable *table, AtomString string) // TODO: this function needs use an efficient structure such as a skip list static struct HNode *get_node_using_index(struct AtomTable *table, long index) { - if (UNLIKELY(index >= table->count)) { + if (UNLIKELY(((size_t) index) >= table->count)) { return NULL; } diff --git a/src/libAtomVM/atom_table.h b/src/libAtomVM/atom_table.h index e78423cac..432a8b19c 100644 --- a/src/libAtomVM/atom_table.h +++ b/src/libAtomVM/atom_table.h @@ -53,7 +53,7 @@ typedef const void *atom_ref_t; struct AtomTable *atom_table_new(); void atom_table_destroy(struct AtomTable *table); -int atom_table_count(struct AtomTable *table); +size_t atom_table_count(struct AtomTable *table); long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts); diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index a8c86f92c..22384962c 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -1558,7 +1558,7 @@ COLD_FUNC static void dump(Context *ctx) fprintf(stderr, "process_count = %zu\n", process_count); fprintf(stderr, "ports_count = %zu\n", ports_count); - fprintf(stderr, "atoms_count = %d\n", atom_table_count(glb->atom_table)); + fprintf(stderr, "atoms_count = %zu\n", atom_table_count(glb->atom_table)); fprintf(stderr, "refc_binary_total_size = %zu\n", refc_binary_total_size(ctx)); } fprintf(stderr, "\n\n**End Of Crash Report**\n"); From c620b860884f45901f38cdb1f121188fc5e4a9b7 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Thu, 20 Mar 2025 21:03:49 +0100 Subject: [PATCH 3/7] Fix warning on non-SMP builds Signed-off-by: Paul Guyot --- src/libAtomVM/atom_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libAtomVM/atom_table.c b/src/libAtomVM/atom_table.c index d91cacf70..ff120ac02 100644 --- a/src/libAtomVM/atom_table.c +++ b/src/libAtomVM/atom_table.c @@ -35,9 +35,9 @@ #define SMP_WRLOCK(htable) smp_rwlock_wrlock(htable->lock) #define SMP_UNLOCK(htable) smp_rwlock_unlock(htable->lock) #else -#define SMP_RDLOCK(htable) -#define SMP_WRLOCK(htable) -#define SMP_UNLOCK(htable) +#define SMP_RDLOCK(htable) UNUSED(htable) +#define SMP_WRLOCK(htable) UNUSED(htable) +#define SMP_UNLOCK(htable) UNUSED(htable) #endif #define DEFAULT_SIZE 8 From 7d3fb4a24157827975a11bc7056f3cf8d787f949 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Mon, 17 Mar 2025 22:39:26 +0100 Subject: [PATCH 4/7] Introduce `atom_index_t` type `atom_index_t` type represents a valid atom index. Signature of functions that returned an atom index that could be an error were modified consequently, introducing a type for the error results of `atom_table_ensure_atoms` and `atom_table_ensure_atom` and removing now redundant `globalcontext_insert_atom` in favor of `globalcontext_make_atom` that returns a term. Signed-off-by: Paul Guyot --- src/libAtomVM/atom.h | 1 + src/libAtomVM/atom_table.c | 65 ++- src/libAtomVM/atom_table.h | 25 +- src/libAtomVM/bif.c | 51 ++- src/libAtomVM/defaultatoms.c | 6 +- src/libAtomVM/externalterm.c | 20 +- src/libAtomVM/globalcontext.c | 10 +- src/libAtomVM/globalcontext.h | 41 +- src/libAtomVM/interop.c | 3 +- src/libAtomVM/module.c | 24 +- src/libAtomVM/module.h | 2 +- src/libAtomVM/term.h | 5 +- .../src/lib/platform_defaultatoms.c | 5 +- .../components/avm_builtins/gpio_driver.c | 11 +- .../components/avm_builtins/i2c_driver.c | 3 +- .../components/avm_builtins/spi_driver.c | 3 +- .../avm_sys/platform_defaultatoms.c | 5 +- .../generic_unix/lib/platform_defaultatoms.c | 5 +- .../rp2/src/lib/platform_defaultatoms.c | 7 +- tests/test-structs.c | 421 ++++++++++++------ 20 files changed, 427 insertions(+), 286 deletions(-) diff --git a/src/libAtomVM/atom.h b/src/libAtomVM/atom.h index c516f7ac4..4ae743ba4 100644 --- a/src/libAtomVM/atom.h +++ b/src/libAtomVM/atom.h @@ -45,6 +45,7 @@ extern "C" { #define ATOM_STR(LENSTR, STR) (LENSTR STR) typedef const void *AtomString; +typedef uint32_t atom_index_t; /** * @brief Gets a C string from an AtomString diff --git a/src/libAtomVM/atom_table.c b/src/libAtomVM/atom_table.c index ff120ac02..6422ec453 100644 --- a/src/libAtomVM/atom_table.c +++ b/src/libAtomVM/atom_table.c @@ -50,13 +50,13 @@ struct HNode { struct HNode *next; AtomString key; - long index; + atom_index_t index; }; struct HNodeGroup { struct HNodeGroup *next; - long first_index; + atom_index_t first_index; uint16_t len; struct HNode nodes[]; @@ -188,21 +188,8 @@ static inline struct HNode *get_node(const struct AtomTable *hash_table, AtomStr return get_node_with_hash(hash_table, string, hash); } -long atom_table_get_index(struct AtomTable *table, AtomString string) -{ - unsigned long hash = sdbm_hash(string, atom_string_len(string)); - - SMP_RDLOCK(table); - - struct HNode *node = get_node_with_hash(table, string, hash); - long result = (node != NULL) ? node->index : ATOM_TABLE_NOT_FOUND; - - SMP_UNLOCK(table); - return result; -} - // TODO: this function needs use an efficient structure such as a skip list -static struct HNode *get_node_using_index(struct AtomTable *table, long index) +static struct HNode *get_node_using_index(struct AtomTable *table, atom_index_t index) { if (UNLIKELY(((size_t) index) >= table->count)) { return NULL; @@ -210,7 +197,7 @@ static struct HNode *get_node_using_index(struct AtomTable *table, long index) struct HNodeGroup *node_group = table->first_node_group; while (node_group) { - long first_index = node_group->first_index; + atom_index_t first_index = node_group->first_index; if (first_index + node_group->len > index) { return &node_group->nodes[index - first_index]; } @@ -221,7 +208,7 @@ static struct HNode *get_node_using_index(struct AtomTable *table, long index) return NULL; } -AtomString atom_table_get_atom_string(struct AtomTable *table, long index) +AtomString atom_table_get_atom_string(struct AtomTable *table, atom_index_t index) { SMP_RDLOCK(table); @@ -264,7 +251,7 @@ int atom_table_cmp_using_atom_index(struct AtomTable *table, int t_atom_index, i return memcmp_result; } -atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, long index, size_t *out_len) +atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, atom_index_t index, size_t *out_len) { SMP_RDLOCK(table); @@ -334,10 +321,10 @@ static inline void insert_node_into_bucket( node->next = maybe_existing_node; } -static inline long insert_node(struct AtomTable *table, struct HNodeGroup *node_group, +static inline atom_index_t insert_node(struct AtomTable *table, struct HNodeGroup *node_group, unsigned long bucket_index, AtomString string) { - long new_index = table->count; + atom_index_t new_index = table->count; table->count++; struct HNode *node = &node_group->nodes[new_index - node_group->first_index]; @@ -398,7 +385,7 @@ static inline bool maybe_rehash(struct AtomTable *table, int new_entries) return do_rehash(table, new_capacity); } -long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts) +enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts, atom_index_t *result) { unsigned long hash = sdbm_hash(string, atom_string_len(string)); SMP_WRLOCK(table); @@ -407,11 +394,12 @@ long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum Ato struct HNode *node = get_node_from_bucket(table, bucket_index, string); if (node) { SMP_UNLOCK(table); - return node->index; + *result = node->index; + return AtomTableEnsureAtomOk; } if (opts & AtomTableAlreadyExisting) { SMP_UNLOCK(table); - return ATOM_TABLE_NOT_FOUND; + return AtomTableEnsureAtomNotFound; } struct HNodeGroup *node_group = table->last_node_group; @@ -419,7 +407,7 @@ long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum Ato node_group = new_node_group(table, DEFAULT_SIZE); if (IS_NULL_PTR(node_group)) { SMP_UNLOCK(table); - return ATOM_TABLE_ALLOC_FAIL; + return AtomTableEnsureAtomAllocFail; } } @@ -429,7 +417,7 @@ long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum Ato uint8_t *buf = malloc(1 + len); if (IS_NULL_PTR(buf)) { SMP_UNLOCK(table); - return ATOM_TABLE_ALLOC_FAIL; + return AtomTableEnsureAtomAllocFail; } memcpy(buf, string, 1 + len); maybe_copied = buf; @@ -439,10 +427,10 @@ long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum Ato bucket_index = hash % table->capacity; } - long new_index = insert_node(table, node_group, bucket_index, maybe_copied); + *result = insert_node(table, node_group, bucket_index, maybe_copied); SMP_UNLOCK(table); - return new_index; + return AtomTableEnsureAtomOk; } static inline int read_encoded_len(const uint8_t **len_bytes) @@ -463,8 +451,11 @@ static inline int read_encoded_len(const uint8_t **len_bytes) } } -int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, - int *translate_table, enum EnsureAtomsOpt opt) +// -1 is not a valid atom index as we're limited to 2^20 +#define ATOM_TABLE_NOT_FOUND_MARKER ((atom_index_t) -1) + +enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, + atom_index_t *translate_table, enum EnsureAtomsOpt opt) { bool is_long_format = (opt & EnsureLongEncoding) != 0; @@ -481,7 +472,7 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun if (UNLIKELY(atom_len < 0)) { fprintf(stderr, "Found invalid atom len."); SMP_UNLOCK(table); - return ATOM_TABLE_INVALID_LEN; + return AtomTableEnsureAtomInvalidLen; } else if (UNLIKELY(atom_len > 255)) { fprintf(stderr, "Unsupported atom length %i bytes.\n" @@ -491,7 +482,7 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun "https://github.com/atomvm/AtomVM/issues\n", atom_len); SMP_UNLOCK(table); - return ATOM_TABLE_INVALID_LEN; + return AtomTableEnsureAtomInvalidLen; } char tmp_old_fmt[256]; tmp_old_fmt[0] = atom_len; @@ -508,7 +499,7 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun translate_table[i] = node->index; } else { new_atoms_count++; - translate_table[i] = ATOM_TABLE_NOT_FOUND; + translate_table[i] = ATOM_TABLE_NOT_FOUND_MARKER; } } @@ -531,12 +522,12 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun next_atom += 1 + atom_len; } - if (translate_table[i] == ATOM_TABLE_NOT_FOUND) { + if (translate_table[i] == ATOM_TABLE_NOT_FOUND_MARKER) { if (!table->last_node_group_avail) { node_group = new_node_group(table, remaining_atoms); if (IS_NULL_PTR(node_group)) { SMP_UNLOCK(table); - return ATOM_TABLE_ALLOC_FAIL; + return AtomTableEnsureAtomAllocFail; } } @@ -545,7 +536,7 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun if (IS_NULL_PTR(atom_copy)) { // we are not going to remove atoms that have already been added up to this one SMP_UNLOCK(table); - return ATOM_TABLE_ALLOC_FAIL; + return AtomTableEnsureAtomAllocFail; } atom_copy[0] = atom_len; memcpy(atom_copy + 1, to_be_copied, atom_len); @@ -566,5 +557,5 @@ int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int coun SMP_UNLOCK(table); - return 0; + return AtomTableEnsureAtomOk; } diff --git a/src/libAtomVM/atom_table.h b/src/libAtomVM/atom_table.h index 432a8b19c..a3f73783e 100644 --- a/src/libAtomVM/atom_table.h +++ b/src/libAtomVM/atom_table.h @@ -24,15 +24,12 @@ #include #include "atom.h" +#include "utils.h" #ifdef __cplusplus extern "C" { #endif -#define ATOM_TABLE_NOT_FOUND -1 -#define ATOM_TABLE_ALLOC_FAIL -2 -#define ATOM_TABLE_INVALID_LEN -3 - struct AtomTable; enum EnsureAtomsOpt @@ -48,6 +45,14 @@ enum AtomTableCopyOpt AtomTableAlreadyExisting = 2 }; +enum AtomTableEnsureAtomResult +{ + AtomTableEnsureAtomOk = 0, + AtomTableEnsureAtomNotFound = -1, + AtomTableEnsureAtomAllocFail = -2, + AtomTableEnsureAtomInvalidLen = -3, +}; + typedef const void *atom_ref_t; struct AtomTable *atom_table_new(); @@ -55,20 +60,18 @@ void atom_table_destroy(struct AtomTable *table); size_t atom_table_count(struct AtomTable *table); -long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts); +enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts, atom_index_t *result) MUST_CHECK; // This function is deprecated and it will be removed. // atom strings should be copied to caller owned buffers. -AtomString atom_table_get_atom_string(struct AtomTable *table, long index); - -long atom_table_get_index(struct AtomTable *table, AtomString string); +AtomString atom_table_get_atom_string(struct AtomTable *table, atom_index_t index); -int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, - int *translate_table, enum EnsureAtomsOpt opts); +enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, + atom_index_t *translate_table, enum EnsureAtomsOpt opts) MUST_CHECK; int atom_table_cmp_using_atom_index( struct AtomTable *table, int t_atom_index, int other_atom_index); -atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, long index, size_t *out_len); +atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, atom_index_t index, size_t *out_len); bool atom_table_is_atom_ref_ascii(struct AtomTable *table, atom_ref_t atom); void atom_table_write_bytes(struct AtomTable *table, atom_ref_t atom, size_t buf_len, void *outbuf); void atom_table_write_cstring( diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index e16e7efd3..80274b5bf 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -31,6 +31,7 @@ #include "overflow_helpers.h" #include "smp.h" #include "term.h" +#include "term_typedef.h" #include "trace.h" #include "unicode.h" #include "utils.h" @@ -1755,16 +1756,25 @@ static term list_to_atom(Context *ctx, term a_list, bool create_new, term *error if (!create_new) { atom_opts |= AtomTableAlreadyExisting; } - long global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts); + atom_index_t global_atom_index; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts, &global_atom_index); free((void *) atom); - if (UNLIKELY(global_atom_index == ATOM_TABLE_NOT_FOUND)) { - *error_reason = BADARG_ATOM; - return term_invalid_term(); - } else if (UNLIKELY(global_atom_index == ATOM_TABLE_ALLOC_FAIL)) { - *error_reason = OUT_OF_MEMORY_ATOM; - return term_invalid_term(); + switch (ensure_result) { + case AtomTableEnsureAtomNotFound: + case AtomTableEnsureAtomInvalidLen: { + *error_reason = BADARG_ATOM; + return term_invalid_term(); + } + case AtomTableEnsureAtomAllocFail: { + *error_reason = OUT_OF_MEMORY_ATOM; + return term_invalid_term(); + } + case AtomTableEnsureAtomOk: { + return term_from_atom_index(global_atom_index); + } + default: + UNREACHABLE(); } - return term_from_atom_index(global_atom_index); } term bif_erlang_binary_to_atom_2(Context *ctx, uint32_t fail_label, int live, term arg1, term arg2) @@ -1855,14 +1865,23 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new, if (!create_new) { atom_opts |= AtomTableAlreadyExisting; } - long global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts); + atom_index_t global_atom_index; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts, &global_atom_index); free((void *) atom); - if (UNLIKELY(global_atom_index == ATOM_TABLE_NOT_FOUND)) { - *error_reason = BADARG_ATOM; - return term_invalid_term(); - } else if (UNLIKELY(global_atom_index == ATOM_TABLE_ALLOC_FAIL)) { - *error_reason = OUT_OF_MEMORY_ATOM; - return term_invalid_term(); + switch (ensure_result) { + case AtomTableEnsureAtomNotFound: + case AtomTableEnsureAtomInvalidLen: { + *error_reason = BADARG_ATOM; + return term_invalid_term(); + } + case AtomTableEnsureAtomAllocFail: { + *error_reason = OUT_OF_MEMORY_ATOM; + return term_invalid_term(); + } + case AtomTableEnsureAtomOk: { + return term_from_atom_index(global_atom_index); + } + default: + UNREACHABLE(); } - return term_from_atom_index(global_atom_index); } diff --git a/src/libAtomVM/defaultatoms.c b/src/libAtomVM/defaultatoms.c index ac4e79a3a..feeec3c9f 100644 --- a/src/libAtomVM/defaultatoms.c +++ b/src/libAtomVM/defaultatoms.c @@ -19,6 +19,7 @@ */ #include "defaultatoms.h" +#include "term.h" #include #include @@ -38,12 +39,13 @@ void defaultatoms_init(GlobalContext *glb) }; #undef X - for (int i = 0; i < PLATFORM_ATOMS_BASE_INDEX; i++) { + for (size_t i = 0; i < PLATFORM_ATOMS_BASE_INDEX; i++) { if (UNLIKELY((size_t) atoms[i][0] != strlen(atoms[i] + 1))) { AVM_ABORT(); } - if (UNLIKELY(globalcontext_insert_atom(glb, atoms[i]) != i)) { + term atom_term = globalcontext_make_atom(glb, atoms[i]); + if (UNLIKELY(term_to_atom_index(atom_term) != i)) { AVM_ABORT(); } } diff --git a/src/libAtomVM/externalterm.c b/src/libAtomVM/externalterm.c index 9018849a1..91dab2daf 100644 --- a/src/libAtomVM/externalterm.c +++ b/src/libAtomVM/externalterm.c @@ -524,10 +524,10 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm } const uint8_t *atom_chars = (const uint8_t *) (external_term_buf + 3); - int global_atom_id; + term atom_term; if (LIKELY(unicode_buf_is_ascii(atom_chars, atom_len))) { // there is a trick here: we are reusing LSB of len field as atom length - global_atom_id = globalcontext_insert_atom_maybe_copy( + atom_term = globalcontext_insert_atom_maybe_copy( glb, (AtomString) (external_term_buf + 2), copy); } else { // need to re-encode latin1 to UTF-8 @@ -544,17 +544,13 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm bitstring_utf8_encode(atom_chars[i], curr_codepoint, &codepoint_size); curr_codepoint += codepoint_size; } - global_atom_id + atom_term = globalcontext_insert_atom_maybe_copy(glb, (AtomString) atom_buf, true); free(atom_buf); } - if (UNLIKELY(global_atom_id) < 0) { - return term_invalid_term(); - } - *eterm_size = 3 + atom_len; - return term_from_atom_index(global_atom_id); + return atom_term; } case SMALL_TUPLE_EXT: @@ -708,13 +704,9 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm } // AtomString first byte is the atom length - int global_atom_id = globalcontext_insert_atom_maybe_copy(glb, (AtomString) (external_term_buf + 1), copy); - if (UNLIKELY(global_atom_id < 0)) { - return term_invalid_term(); - } - + term atom_term = globalcontext_insert_atom_maybe_copy(glb, (AtomString) (external_term_buf + 1), copy); *eterm_size = 2 + atom_len; - return term_from_atom_index(global_atom_id); + return atom_term; } case NEW_PID_EXT: { diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index 157b547ff..0320f576a 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -604,7 +604,7 @@ term globalcontext_get_registered_name_process(GlobalContext *glb, int local_pro return term_invalid_term(); } -bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, int atom_index_a, AtomString atom_string_b) +bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, atom_index_t atom_index_a, AtomString atom_string_b) { AtomString atom_string_a; atom_string_a = atom_table_get_atom_string(glb->atom_table, atom_index_a); @@ -626,11 +626,13 @@ AtomString globalcontext_atomstring_from_term(GlobalContext *glb, term t) term globalcontext_existing_term_from_atom_string(GlobalContext *glb, AtomString atom_string) { - long atom_index = atom_table_get_index(glb->atom_table, atom_string); - if (UNLIKELY(atom_index == ATOM_TABLE_NOT_FOUND)) { + atom_index_t global_atom_index; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom( + glb->atom_table, atom_string, AtomTableAlreadyExisting, &global_atom_index); + if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { return term_invalid_term(); } - return term_from_atom_index(atom_index); + return term_from_atom_index(global_atom_index); } int globalcontext_insert_module(GlobalContext *global, Module *module) diff --git a/src/libAtomVM/globalcontext.h b/src/libAtomVM/globalcontext.h index 7e64f2a78..96d226315 100644 --- a/src/libAtomVM/globalcontext.h +++ b/src/libAtomVM/globalcontext.h @@ -394,26 +394,19 @@ void globalcontext_maybe_unregister_process_id(GlobalContext *glb, int process_i * @details Inserts an atom into the global atoms table and returns its id. * @param glb the global context. * @param atom_string the atom string that will be added to the global atoms table, it will not be copied so it must stay allocated and valid. - * @param copy if non-zero, make a copy of the input atom_string if the atom is not already in the table. The table + * @param copy if `true`, make a copy of the input atom_string if the atom is not already in the table. The table * assumes "ownership" of the allocated memory. - * @returns newly added atom id or -1 in case of failure. + * @returns newly added atom id or term_invalid_term() in case of failure. */ -static inline int globalcontext_insert_atom_maybe_copy(GlobalContext *glb, AtomString atom_string, int copy) +static inline term globalcontext_insert_atom_maybe_copy(GlobalContext *glb, AtomString atom_string, bool copy) { - long index = atom_table_ensure_atom( - glb->atom_table, atom_string, copy ? AtomTableCopyAtom : AtomTableNoOpts); - if (UNLIKELY(index) < 0) { - return -1; + atom_index_t global_atom_index; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom( + glb->atom_table, atom_string, copy ? AtomTableCopyAtom : AtomTableNoOpts, &global_atom_index); + if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { + return term_invalid_term(); } - return index; -} - -/** - * @brief equivalent to globalcontext_insert_atom_maybe_copy(glb, atom_string, 0); - */ -static inline int globalcontext_insert_atom(GlobalContext *glb, AtomString atom_string) -{ - return globalcontext_insert_atom_maybe_copy(glb, atom_string, 0); + return term_from_atom_index(global_atom_index); } /** @@ -425,7 +418,7 @@ static inline int globalcontext_insert_atom(GlobalContext *glb, AtomString atom_ * @param atom_string_b an atom string, which is the atom length followed by atom characters. * @returns true if they both refer to the same atom, otherwise false. */ -bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, int atom_index_a, AtomString atom_string_b); +bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, atom_index_t atom_index_a, AtomString atom_string_b); /** * @brief Compares a term with an AtomString. @@ -442,23 +435,23 @@ static inline bool globalcontext_is_term_equal_to_atom_string(GlobalContext *glo return false; } - int atom_index_a = term_to_atom_index(atom_a); + atom_index_t atom_index_a = term_to_atom_index(atom_a); return globalcontext_is_atom_index_equal_to_atom_string(global, atom_index_a, atom_string_b); } /** - * @brief Returns a term representing an atom, from the suppliend string + * @brief Returns a term representing an atom, from the supplied string. * * @details Converts a string to an atom. Note that this function may have a side-effect on the - * global context. + * global context. It doesn't copy the atom string and is meant to be called with + * constant atom strings in code. * @param glb pointer to the global context - * @param string an AtomString + * @param atom_string an AtomString * @return an atom term formed from the supplied atom string. */ -static inline term globalcontext_make_atom(GlobalContext *glb, AtomString string) +static inline term globalcontext_make_atom(GlobalContext *glb, AtomString atom_string) { - int global_atom_index = globalcontext_insert_atom(glb, string); - return term_from_atom_index(global_atom_index); + return globalcontext_insert_atom_maybe_copy(glb, atom_string, false); } /** diff --git a/src/libAtomVM/interop.c b/src/libAtomVM/interop.c index 16a2113fc..b8ba2d1fc 100644 --- a/src/libAtomVM/interop.c +++ b/src/libAtomVM/interop.c @@ -692,8 +692,7 @@ term interop_atom_term_select_atom(const AtomStringIntPair *table, int value, Gl { for (int i = 0; table[i].as_val != NULL; i++) { if (value == table[i].i_val) { - int global_atom_index = globalcontext_insert_atom(global, table[i].as_val); - return term_from_atom_index(global_atom_index); + return globalcontext_make_atom(global, table[i].as_val); } } return term_invalid_term(); diff --git a/src/libAtomVM/module.c b/src/libAtomVM/module.c index 73de8e1af..2d206378a 100644 --- a/src/libAtomVM/module.c +++ b/src/libAtomVM/module.c @@ -21,6 +21,7 @@ #include "module.h" #include "atom.h" +#include "atom_table.h" #include "bif.h" #include "context.h" #include "externalterm.h" @@ -87,16 +88,23 @@ static enum ModuleLoadResult module_populate_atoms_table(Module *this_module, ui return MODULE_ERROR_FAILED_ALLOCATION; } - long ensure_result = atom_table_ensure_atoms( + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atoms( glb->atom_table, current_atom, atoms_count, this_module->local_atoms_to_global_table + 1, ensure_opts); - if (UNLIKELY(ensure_result == ATOM_TABLE_ALLOC_FAIL)) { - fprintf(stderr, "Cannot allocate memory while loading module (line: %i).\n", __LINE__); - return MODULE_ERROR_FAILED_ALLOCATION; - } else if (UNLIKELY(ensure_result == ATOM_TABLE_INVALID_LEN)) { - return MODULE_ERROR_INVALID; + switch (ensure_result) { + case AtomTableEnsureAtomAllocFail: { + fprintf(stderr, "Cannot allocate memory while loading module (line: %i).\n", __LINE__); + return MODULE_ERROR_FAILED_ALLOCATION; + } + case AtomTableEnsureAtomInvalidLen: + case AtomTableEnsureAtomNotFound: { + return MODULE_ERROR_INVALID; + } + case AtomTableEnsureAtomOk: { + return MODULE_LOAD_OK; + } + default: + UNREACHABLE(); } - - return MODULE_LOAD_OK; } static enum ModuleLoadResult module_build_imported_functions_table(Module *this_module, uint8_t *table_data, GlobalContext *glb) diff --git a/src/libAtomVM/module.h b/src/libAtomVM/module.h index 12efdb8dd..57185c724 100644 --- a/src/libAtomVM/module.h +++ b/src/libAtomVM/module.h @@ -117,7 +117,7 @@ struct Module struct LiteralEntry *literals_table; - int *local_atoms_to_global_table; + atom_index_t *local_atoms_to_global_table; void *module_platform_data; diff --git a/src/libAtomVM/term.h b/src/libAtomVM/term.h index 79be5cd7d..14b927976 100644 --- a/src/libAtomVM/term.h +++ b/src/libAtomVM/term.h @@ -37,6 +37,7 @@ #include #include +#include "atom.h" #include "memory.h" #include "refc_binary.h" #include "utils.h" @@ -806,7 +807,7 @@ static inline term term_nil() * @param t the term that will be converted to atom table index. t must be a valid atom term. * @return a global atom table index. */ -static inline int term_to_atom_index(term t) +static inline atom_index_t term_to_atom_index(term t) { return t >> 6; } @@ -818,7 +819,7 @@ static inline int term_to_atom_index(term t) * @param atom_index global atoms table index. * @return a term that encapsulates the atom. */ -static inline term term_from_atom_index(int atom_index) +static inline term term_from_atom_index(atom_index_t atom_index) { return TERM_FROM_ATOM_INDEX(atom_index); } diff --git a/src/platforms/emscripten/src/lib/platform_defaultatoms.c b/src/platforms/emscripten/src/lib/platform_defaultatoms.c index 412d03b64..50172c738 100644 --- a/src/platforms/emscripten/src/lib/platform_defaultatoms.c +++ b/src/platforms/emscripten/src/lib/platform_defaultatoms.c @@ -37,12 +37,13 @@ void platform_defaultatoms_init(GlobalContext *glb) }; #undef X - for (int i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { + for (size_t i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { if (UNLIKELY((size_t) atoms[i][0] != strlen(atoms[i] + 1))) { AVM_ABORT(); } - if (UNLIKELY(globalcontext_insert_atom(glb, atoms[i]) != i + PLATFORM_ATOMS_BASE_INDEX)) { + term atom_term = globalcontext_make_atom(glb, atoms[i]); + if (UNLIKELY(term_to_atom_index(atom_term) != i + PLATFORM_ATOMS_BASE_INDEX)) { AVM_ABORT(); } } diff --git a/src/platforms/esp32/components/avm_builtins/gpio_driver.c b/src/platforms/esp32/components/avm_builtins/gpio_driver.c index 0170b6209..757965292 100644 --- a/src/platforms/esp32/components/avm_builtins/gpio_driver.c +++ b/src/platforms/esp32/components/avm_builtins/gpio_driver.c @@ -293,8 +293,7 @@ static inline term gpio_digital_read(term gpio_num_term) void gpio_driver_init(GlobalContext *global) { - int index = globalcontext_insert_atom(global, gpio_driver_atom); - gpio_driver = term_from_atom_index(index); + gpio_driver = globalcontext_make_atom(global, gpio_driver_atom); } Context *gpio_driver_create_port(GlobalContext *global, term opts) @@ -313,7 +312,7 @@ Context *gpio_driver_create_port(GlobalContext *global, term opts) ctx->platform_data = gpio_data; term reg_name_term = globalcontext_make_atom(global, gpio_atom); - int atom_index = term_to_atom_index(reg_name_term); + atom_index_t atom_index = term_to_atom_index(reg_name_term); term local_port_id = term_port_from_local_process_id(ctx->process_id); if (UNLIKELY(!globalcontext_register_process(ctx->global, atom_index, local_port_id))) { @@ -328,7 +327,11 @@ Context *gpio_driver_create_port(GlobalContext *global, term opts) static term gpiodriver_close(Context *ctx) { GlobalContext *glb = ctx->global; - int gpio_atom_index = atom_table_ensure_atom(glb->atom_table, gpio_atom, AtomTableNoOpts); + term gpio_atom_term = globalcontext_make_atom(glb, gpio_atom); + if (UNLIKELY(!term_is_invalid_term(gpio_atom_term))) { + return ERROR_ATOM; + } + atom_index_t gpio_atom_index = term_to_atom_index(gpio_atom_term); if (UNLIKELY(globalcontext_get_registered_process(glb, gpio_atom_index) == UNDEFINED_ATOM)) { return ERROR_ATOM; } diff --git a/src/platforms/esp32/components/avm_builtins/i2c_driver.c b/src/platforms/esp32/components/avm_builtins/i2c_driver.c index cd7753723..d9e981803 100644 --- a/src/platforms/esp32/components/avm_builtins/i2c_driver.c +++ b/src/platforms/esp32/components/avm_builtins/i2c_driver.c @@ -104,8 +104,7 @@ struct I2CData void i2c_driver_init(GlobalContext *global) { - int index = globalcontext_insert_atom(global, i2c_driver_atom); - i2c_driver = term_from_atom_index(index); + i2c_driver = globalcontext_make_atom(global, i2c_driver_atom); } Context *i2c_driver_create_port(GlobalContext *global, term opts) diff --git a/src/platforms/esp32/components/avm_builtins/spi_driver.c b/src/platforms/esp32/components/avm_builtins/spi_driver.c index cd71ea3d5..64ca0b49a 100644 --- a/src/platforms/esp32/components/avm_builtins/spi_driver.c +++ b/src/platforms/esp32/components/avm_builtins/spi_driver.c @@ -193,8 +193,7 @@ static void debug_devcfg(spi_device_interface_config_t *devcfg) void spi_driver_init(GlobalContext *global) { - int index = globalcontext_insert_atom(global, spi_driver_atom); - spi_driver = term_from_atom_index(index); + spi_driver = globalcontext_make_atom(global, spi_driver_atom); } Context *spi_driver_create_port(GlobalContext *global, term opts) diff --git a/src/platforms/esp32/components/avm_sys/platform_defaultatoms.c b/src/platforms/esp32/components/avm_sys/platform_defaultatoms.c index 412d03b64..50172c738 100644 --- a/src/platforms/esp32/components/avm_sys/platform_defaultatoms.c +++ b/src/platforms/esp32/components/avm_sys/platform_defaultatoms.c @@ -37,12 +37,13 @@ void platform_defaultatoms_init(GlobalContext *glb) }; #undef X - for (int i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { + for (size_t i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { if (UNLIKELY((size_t) atoms[i][0] != strlen(atoms[i] + 1))) { AVM_ABORT(); } - if (UNLIKELY(globalcontext_insert_atom(glb, atoms[i]) != i + PLATFORM_ATOMS_BASE_INDEX)) { + term atom_term = globalcontext_make_atom(glb, atoms[i]); + if (UNLIKELY(term_to_atom_index(atom_term) != i + PLATFORM_ATOMS_BASE_INDEX)) { AVM_ABORT(); } } diff --git a/src/platforms/generic_unix/lib/platform_defaultatoms.c b/src/platforms/generic_unix/lib/platform_defaultatoms.c index 412d03b64..50172c738 100644 --- a/src/platforms/generic_unix/lib/platform_defaultatoms.c +++ b/src/platforms/generic_unix/lib/platform_defaultatoms.c @@ -37,12 +37,13 @@ void platform_defaultatoms_init(GlobalContext *glb) }; #undef X - for (int i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { + for (size_t i = 0; i < ATOM_FIRST_AVAIL_INDEX - PLATFORM_ATOMS_BASE_INDEX; i++) { if (UNLIKELY((size_t) atoms[i][0] != strlen(atoms[i] + 1))) { AVM_ABORT(); } - if (UNLIKELY(globalcontext_insert_atom(glb, atoms[i]) != i + PLATFORM_ATOMS_BASE_INDEX)) { + term atom_term = globalcontext_make_atom(glb, atoms[i]); + if (UNLIKELY(term_to_atom_index(atom_term) != i + PLATFORM_ATOMS_BASE_INDEX)) { AVM_ABORT(); } } diff --git a/src/platforms/rp2/src/lib/platform_defaultatoms.c b/src/platforms/rp2/src/lib/platform_defaultatoms.c index 9674f8304..809c6bff0 100644 --- a/src/platforms/rp2/src/lib/platform_defaultatoms.c +++ b/src/platforms/rp2/src/lib/platform_defaultatoms.c @@ -24,11 +24,8 @@ static const char *const pico_atom = ATOM_STR("\x4", "pico"); void platform_defaultatoms_init(GlobalContext *glb) { - int ok = 1; - - ok &= globalcontext_insert_atom(glb, pico_atom) == PICO_ATOM_INDEX; - - if (!ok) { + term atom_term = globalcontext_make_atom(glb, pico_atom); + if (UNLIKELY(term_to_atom_index(atom_term) != PICO_ATOM_INDEX)) { AVM_ABORT(); } } diff --git a/tests/test-structs.c b/tests/test-structs.c index d980b3660..95462f6a8 100644 --- a/tests/test-structs.c +++ b/tests/test-structs.c @@ -274,144 +274,254 @@ void test_valueshashtable() } } -int insert_atoms_into_atom_table(struct AtomTable *table) +atom_index_t insert_atoms_into_atom_table(struct AtomTable *table) { - int decimals_index; - - atom_table_ensure_atom(table, false_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, true_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, ok_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, error_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, undefined_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, badarg_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, badarith_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, badarity_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, badfun_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, function_clause_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, try_clause_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, out_of_memory_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, overflow_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, system_limit_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, flush_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, heap_size_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, latin1_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, max_heap_size_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, memory_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, message_queue_len_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, puts_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, stack_size_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, min_heap_size_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, process_count_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, port_count_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, atom_count_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, system_architecture_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, wordsize_atom, AtomTableNoOpts); - - decimals_index = atom_table_ensure_atom(table, decimals_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, scientific_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, compact_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, badmatch_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, case_clause_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, if_clause_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, throw_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, low_entropy_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, unsupported_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, used_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, all_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, start_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, undef_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, vm_abort_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, link_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, monitor_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, normal_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, down_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, process_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, nocatch_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, refc_binary_info_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, noproc_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, trap_exit_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, exit_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, badmap_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, badkey_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, none_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, io_request_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, io_reply_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, put_chars_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, lowercase_exit_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, atomvm_version_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, second_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, millisecond_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, microsecond_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, infinity_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, timeout_value_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, schedulers_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, schedulers_online_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, append_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, private_append_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, binary_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, integer_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, little_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, native_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, string_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, utf8_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, utf16_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, utf32_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, badrecord_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, copy_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, reuse_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, ensure_at_least_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, ensure_exactly_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, skip_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, get_tail_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, equal_colon_equal_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, signed_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, machine_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, avm_floatsize_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, close_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, closed_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, port_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, info_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, module_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, select_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, ready_input_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, ready_output_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, attributes_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, compile_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, exports_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, incomplete_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, kill_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, killed_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, links_atom, AtomTableNoOpts); - - atom_table_ensure_atom(table, total_heap_size_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, atomvm_heap_growth_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, bounded_free_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, minimum_atom, AtomTableNoOpts); - atom_table_ensure_atom(table, fibonacci_atom, AtomTableNoOpts); + atom_index_t global_atom_index; + atom_index_t decimals_index; + enum AtomTableEnsureAtomResult r; + + r = atom_table_ensure_atom(table, false_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, true_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, ok_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, error_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, undefined_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badarg_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badarith_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badarity_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badfun_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, function_clause_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, try_clause_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, out_of_memory_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, overflow_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, system_limit_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, flush_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, heap_size_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, latin1_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, max_heap_size_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, memory_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, message_queue_len_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, puts_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, stack_size_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, min_heap_size_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, process_count_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, port_count_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, atom_count_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, system_architecture_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, wordsize_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, decimals_atom, AtomTableNoOpts, &decimals_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, scientific_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, compact_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badmatch_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, case_clause_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, if_clause_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, throw_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, low_entropy_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, unsupported_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, used_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, all_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, start_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, undef_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, vm_abort_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, link_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, monitor_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, normal_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, down_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, process_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, nocatch_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, refc_binary_info_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, noproc_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, trap_exit_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, exit_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badmap_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badkey_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, none_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, io_request_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, io_reply_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, put_chars_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, lowercase_exit_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, atomvm_version_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, second_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, millisecond_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, microsecond_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, infinity_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, timeout_value_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, schedulers_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, schedulers_online_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, append_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, private_append_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, binary_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, integer_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, little_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, native_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, string_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, utf8_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, utf16_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, utf32_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, badrecord_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, copy_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, reuse_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, ensure_at_least_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, ensure_exactly_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, skip_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, get_tail_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, equal_colon_equal_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, signed_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, machine_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, avm_floatsize_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, close_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, closed_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, port_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, info_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, module_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, select_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, ready_input_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, ready_output_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, attributes_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, compile_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, exports_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, incomplete_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, kill_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, killed_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, links_atom, AtomTableNoOpts, &global_atom_index); + + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, total_heap_size_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, atomvm_heap_growth_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, bounded_free_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, minimum_atom, AtomTableNoOpts, &global_atom_index); + assert(r == AtomTableEnsureAtomOk); + r = atom_table_ensure_atom(table, fibonacci_atom, AtomTableNoOpts, &global_atom_index); return decimals_index; } @@ -420,21 +530,40 @@ void test_atom_table() { struct AtomTable *table = atom_table_new(); - assert(atom_table_get_index(table, "\x4" "ciao") == ATOM_TABLE_NOT_FOUND); + enum AtomTableEnsureAtomResult r; + atom_index_t new_index; + r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableAlreadyExisting, &new_index); + assert(r == AtomTableEnsureAtomNotFound); - assert(atom_table_ensure_atom(table, "\x3" "bar", AtomTableNoOpts) == 0); - assert(atom_table_ensure_atom(table, "\x4" "ciao", AtomTableNoOpts) == 1); - assert(atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts) == 2); - assert(atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts) == 2); + r = atom_table_ensure_atom(table, "\x3" "bar", AtomTableNoOpts, &new_index); + assert(r == AtomTableEnsureAtomOk); + assert(new_index == 0); - assert(atom_table_get_index(table, "\x4" "ciao") == 1); + atom_index_t ciao_index; + r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableNoOpts, &ciao_index); + assert(r == AtomTableEnsureAtomOk); + assert(ciao_index == 1); + + atom_index_t foo_index; + r = atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts, &foo_index); + assert(r == AtomTableEnsureAtomOk); + assert(foo_index == 2); + + r = atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts, &foo_index); + assert(r == AtomTableEnsureAtomOk); + assert(foo_index == 2); + + r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableAlreadyExisting, &ciao_index); + assert(r == AtomTableEnsureAtomOk); + assert(ciao_index == 1); assert(((char *) atom_table_get_atom_string(table, 0))[0] == 3); - int decimals_index = insert_atoms_into_atom_table(table); + atom_index_t decimals_index = insert_atoms_into_atom_table(table); - assert(atom_table_get_index(table, "\x8" "decimals") == decimals_index); - assert(atom_table_ensure_atom(table, "\x8" "decimals", AtomTableNoOpts) == decimals_index); + r = atom_table_ensure_atom(table, "\x8" "decimals", AtomTableNoOpts, &new_index); + assert(r == AtomTableEnsureAtomOk); + assert(new_index == decimals_index); atom_table_destroy(table); } From 2fd37e6146196b2aa51f53032b47b190830a9ddd Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Mon, 17 Mar 2025 23:04:27 +0100 Subject: [PATCH 5/7] Factorize mfa as a key logic Update signature of `atom_write_mfa` so it takes atom length and data separately to prepare for longer atoms. Signed-off-by: Paul Guyot --- src/libAtomVM/atom.c | 8 +++---- src/libAtomVM/atom.h | 8 ++++--- src/libAtomVM/bif.c | 7 ++---- src/libAtomVM/bif.h | 2 +- src/libAtomVM/module.c | 10 +++++---- src/libAtomVM/nifs.c | 40 ++++++++++++----------------------- src/libAtomVM/nifs.h | 2 +- src/libAtomVM/opcodesswitch.h | 6 ++++-- src/libAtomVM/term_typedef.h | 6 ++++++ 9 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/libAtomVM/atom.c b/src/libAtomVM/atom.c index 102e93594..401b22a62 100644 --- a/src/libAtomVM/atom.c +++ b/src/libAtomVM/atom.c @@ -87,19 +87,17 @@ static void utoa10(unsigned int int_value, char *integer_string) integer_string[integer_string_len] = '\0'; } -void atom_write_mfa(char *buf, size_t buf_size, AtomString module, AtomString function, unsigned int arity) +void atom_write_mfa(char *buf, size_t buf_size, size_t module_name_len, const void *module_data, size_t function_name_len, const void *function_data, unsigned int arity) { - size_t module_name_len = atom_string_len(module); - memcpy(buf, atom_string_data(module), module_name_len); + memcpy(buf, module_data, module_name_len); buf[module_name_len] = ':'; - size_t function_name_len = atom_string_len(function); if (UNLIKELY((module_name_len + 1 + function_name_len + 1 + 4 + 1 > buf_size))) { fprintf(stderr, "Insufficient room to write mfa.\n"); AVM_ABORT(); } - memcpy(buf + module_name_len + 1, atom_string_data(function), function_name_len); + memcpy(buf + module_name_len + 1, function_data, function_name_len); buf[module_name_len + function_name_len + 1] = '/'; utoa10(arity, buf + module_name_len + 1 + function_name_len + 1); diff --git a/src/libAtomVM/atom.h b/src/libAtomVM/atom.h index 4ae743ba4..0c7da7a71 100644 --- a/src/libAtomVM/atom.h +++ b/src/libAtomVM/atom.h @@ -99,11 +99,13 @@ static inline const void *atom_string_data(AtomString atom_str) * buffer size. * @param buf the buffer to write into * @param buf_size the amount of room in the buffer - * @param module the module name - * @param function the function name + * @param module_name_len length of the module name + * @param module_data the module name + * @param function_name_len length of the function name + * @param function_data the function name * @param arity the function arity */ -void atom_write_mfa(char *buf, size_t buf_size, AtomString module, AtomString function, unsigned int arity); +void atom_write_mfa(char *buf, size_t buf_size, size_t module_name_len, const void *module_data, size_t function_name_len, const void *function_data, unsigned int arity); #ifdef __cplusplus } diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index 80274b5bf..2fe4c651f 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -59,12 +59,9 @@ RAISE_ERROR_BIF(fail_label, BADARG_ATOM); \ } -const struct ExportedFunction *bif_registry_get_handler(AtomString module, AtomString function, int arity) +const struct ExportedFunction *bif_registry_get_handler(const char *mfa) { - char bifname[MAX_BIF_NAME_LEN]; - - atom_write_mfa(bifname, MAX_BIF_NAME_LEN, module, function, arity); - const BifNameAndPtr *nameAndPtr = in_word_set(bifname, strlen(bifname)); + const BifNameAndPtr *nameAndPtr = in_word_set(mfa, strlen(mfa)); if (!nameAndPtr) { return NULL; } diff --git a/src/libAtomVM/bif.h b/src/libAtomVM/bif.h index d895057dc..251971bfd 100644 --- a/src/libAtomVM/bif.h +++ b/src/libAtomVM/bif.h @@ -39,7 +39,7 @@ extern "C" { #define MAX_BIF_NAME_LEN 260 -const struct ExportedFunction *bif_registry_get_handler(AtomString module, AtomString function, int arity); +const struct ExportedFunction *bif_registry_get_handler(const char *mfa); term bif_erlang_self_0(Context *ctx); term bif_erlang_node_0(Context *ctx); diff --git a/src/libAtomVM/module.c b/src/libAtomVM/module.c index 2d206378a..62a517cbc 100644 --- a/src/libAtomVM/module.c +++ b/src/libAtomVM/module.c @@ -123,13 +123,15 @@ static enum ModuleLoadResult module_build_imported_functions_table(Module *this_ AtomString module_atom = module_get_atom_string_by_id(this_module, local_module_atom_index, glb); AtomString function_atom = module_get_atom_string_by_id(this_module, local_function_atom_index, glb); uint32_t arity = READ_32_UNALIGNED(table_data + i * 12 + 8 + 12); + char mfa[MAX_MFA_NAME_LEN]; + atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_atom), atom_string_data(module_atom), atom_string_len(function_atom), atom_string_data(function_atom), arity); - const struct ExportedFunction *bif = bif_registry_get_handler(module_atom, function_atom, arity); + const struct ExportedFunction *bif = bif_registry_get_handler(mfa); if (bif) { this_module->imported_funcs[i] = bif; } else { - this_module->imported_funcs[i] = &nifs_get(module_atom, function_atom, arity)->base; + this_module->imported_funcs[i] = &nifs_get(mfa)->base; } if (!this_module->imported_funcs[i]) { @@ -472,8 +474,8 @@ const struct ExportedFunction *module_resolve_function0(Module *mod, int import_ if (LIKELY(found_module != NULL)) { int exported_label = module_search_exported_function(found_module, function_name_atom, arity, glb); if (exported_label == 0) { - char buf[256]; - atom_write_mfa(buf, 256, module_name_atom, function_name_atom, arity); + char buf[MAX_MFA_NAME_LEN]; + atom_write_mfa(buf, sizeof(buf), atom_string_len(module_name_atom), atom_string_data(module_name_atom), atom_string_len(function_name_atom), atom_string_data(function_name_atom), arity); fprintf(stderr, "Warning: function %s cannot be resolved.\n", buf); return NULL; } diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index e044dede8..fef03bbd7 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -64,7 +64,6 @@ #include "zlib.h" #endif -#define MAX_NIF_NAME_LEN 260 #define FLOAT_BUF_SIZE 64 #define RAISE(a, b) \ @@ -941,30 +940,11 @@ DEFINE_MATH_NIF(tanh) #include "nifs_hash.h" #pragma GCC diagnostic pop -const struct Nif *nifs_get(AtomString module, AtomString function, int arity) +const struct Nif *nifs_get(const char *mfa) { - char nifname[MAX_NIF_NAME_LEN]; - - int module_name_len = atom_string_len(module); - memcpy(nifname, atom_string_data(module), module_name_len); - - nifname[module_name_len] = ':'; - - int function_name_len = atom_string_len(function); - if (UNLIKELY((arity > 9) || (module_name_len + function_name_len + 4 > MAX_NIF_NAME_LEN))) { - // In AtomVM NIFs are limited to 9 parameters - return NULL; - } - memcpy(nifname + module_name_len + 1, atom_string_data(function), function_name_len); - - //TODO: handle NIFs with more than 9 parameters - nifname[module_name_len + function_name_len + 1] = '/'; - nifname[module_name_len + function_name_len + 2] = '0' + arity; - nifname[module_name_len + function_name_len + 3] = 0; - - const NifNameAndNifPtr *nameAndPtr = nif_in_word_set(nifname, strlen(nifname)); + const NifNameAndNifPtr *nameAndPtr = nif_in_word_set(mfa, strlen(mfa)); if (!nameAndPtr) { - return platform_nifs_get_nif(nifname); + return platform_nifs_get_nif(mfa); } return nameAndPtr->nif; @@ -3886,16 +3866,22 @@ static term nif_erlang_function_exported(Context *ctx, int argc, term argv[]) VALIDATE_VALUE(function, term_is_atom); VALIDATE_VALUE(arity_term, term_is_integer); - AtomString module_name = globalcontext_atomstring_from_term(ctx->global, module); - AtomString function_name = globalcontext_atomstring_from_term(ctx->global, function); + atom_index_t module_name_ix = term_to_atom_index(module); + AtomString module_name = atom_table_get_atom_string(ctx->global->atom_table, module_name_ix); + atom_index_t function_name_ix = term_to_atom_index(function); + AtomString function_name = atom_table_get_atom_string(ctx->global->atom_table, function_name_ix); + avm_int_t arity = term_to_int(arity_term); - const struct ExportedFunction *bif = bif_registry_get_handler(module_name, function_name, arity); + char mfa[MAX_MFA_NAME_LEN]; + atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_name), atom_string_data(module_name), atom_string_len(function_name), atom_string_data(function_name), arity); + + const struct ExportedFunction *bif = bif_registry_get_handler(mfa); if (bif) { return TRUE_ATOM; } - struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, arity); + struct Nif *nif = (struct Nif *) nifs_get(mfa); if (nif) { return TRUE_ATOM; } diff --git a/src/libAtomVM/nifs.h b/src/libAtomVM/nifs.h index 7e6a46fac..a569f42c1 100644 --- a/src/libAtomVM/nifs.h +++ b/src/libAtomVM/nifs.h @@ -46,7 +46,7 @@ extern "C" { ctx->x[1] = (error_type_atom); \ return term_invalid_term(); -const struct Nif *nifs_get(AtomString module, AtomString function, int arity); +const struct Nif *nifs_get(const char *mfa); // spawn opt is used by distribution nifs term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]); diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index 22384962c..5762d8c65 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -1698,7 +1698,9 @@ term make_fun(Context *ctx, const Module *mod, int fun_index, term argv[]) static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString function_name, int arity, term *return_value) { - const struct ExportedFunction *exported_bif = bif_registry_get_handler(module_name, function_name, arity); + char mfa[MAX_MFA_NAME_LEN]; + atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_name), atom_string_data(module_name), atom_string_len(function_name), atom_string_data(function_name), arity); + const struct ExportedFunction *exported_bif = bif_registry_get_handler(mfa); if (exported_bif) { if (exported_bif->type == GCBIFFunctionType) { const struct GCBif *gcbif = EXPORTED_FUNCTION_TO_GCBIF(exported_bif); @@ -1735,7 +1737,7 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f } } - struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, arity); + struct Nif *nif = (struct Nif *) nifs_get(mfa); if (nif) { *return_value = nif->nif_ptr(ctx, arity, ctx->x); return true; diff --git a/src/libAtomVM/term_typedef.h b/src/libAtomVM/term_typedef.h index f9f623565..14cbb408d 100644 --- a/src/libAtomVM/term_typedef.h +++ b/src/libAtomVM/term_typedef.h @@ -144,4 +144,10 @@ typedef union { avm_float_t f; } float_term_t; +// Quite a low value, BEAM is 255 + 255 + 1 + strlen(max(arity)) +// This buffer is typically allocated on C stack +// This is a hard limit for bifs and nifs. It currently is only used for +// printing error messages for other functions. +#define MAX_MFA_NAME_LEN 260 + #endif From 2ab1acb078bee68893518fe683068b05c90f560e Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Thu, 20 Mar 2025 22:08:17 +0100 Subject: [PATCH 6/7] Use valueshashtable for modules and remove atomshashtable Change signature of `globalcontext_get_module` to get an `atom_index_t` to refer to a given module. Signed-off-by: Paul Guyot --- src/libAtomVM/CMakeLists.txt | 2 - src/libAtomVM/atom_table.c | 24 +++++ src/libAtomVM/atom_table.h | 12 +++ src/libAtomVM/atomshashtable.c | 167 -------------------------------- src/libAtomVM/atomshashtable.h | 58 ----------- src/libAtomVM/globalcontext.c | 16 ++- src/libAtomVM/globalcontext.h | 5 +- src/libAtomVM/module.c | 2 +- src/libAtomVM/module.h | 2 - src/libAtomVM/nifs.c | 20 ++-- src/libAtomVM/opcodesswitch.h | 6 +- src/libAtomVM/valueshashtable.c | 24 ++--- src/libAtomVM/valueshashtable.h | 15 ++- tests/test-structs.c | 95 ------------------ 14 files changed, 82 insertions(+), 366 deletions(-) delete mode 100644 src/libAtomVM/atomshashtable.c delete mode 100644 src/libAtomVM/atomshashtable.h diff --git a/src/libAtomVM/CMakeLists.txt b/src/libAtomVM/CMakeLists.txt index 3af3819ec..dda166274 100644 --- a/src/libAtomVM/CMakeLists.txt +++ b/src/libAtomVM/CMakeLists.txt @@ -23,7 +23,6 @@ project (libAtomVM) set(HEADER_FILES atom.h - atomshashtable.h atom_table.h avmpack.h bif.h @@ -75,7 +74,6 @@ set(HEADER_FILES set(SOURCE_FILES atom.c - atomshashtable.c atom_table.c avmpack.c bif.c diff --git a/src/libAtomVM/atom_table.c b/src/libAtomVM/atom_table.c index 6422ec453..f97a17c6c 100644 --- a/src/libAtomVM/atom_table.c +++ b/src/libAtomVM/atom_table.c @@ -267,6 +267,30 @@ atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, atom_index_t return node; } +char *atom_table_atom_to_new_cstring(struct AtomTable *table, atom_index_t atom_index, const char *suffix) +{ + AtomString atom_string = atom_table_get_atom_string(table, atom_index); + size_t atom_len = atom_string_len(atom_string); + const uint8_t *atom_data = atom_string_data(atom_string); + size_t suffix_len = 0; + if (suffix) { + suffix_len = strlen(suffix); + } + + char *result = malloc(atom_len + suffix_len + 1); + if (IS_NULL_PTR(result)) { + return NULL; + } + + memcpy(result, atom_data, atom_len); + if (suffix) { + memcpy(result + atom_len, suffix, suffix_len); + } + result[atom_len + suffix_len] = 0; + + return result; +} + bool atom_table_is_atom_ref_ascii(struct AtomTable *table, atom_ref_t atom) { SMP_RDLOCK(table); diff --git a/src/libAtomVM/atom_table.h b/src/libAtomVM/atom_table.h index a3f73783e..0f4b496d8 100644 --- a/src/libAtomVM/atom_table.h +++ b/src/libAtomVM/atom_table.h @@ -77,6 +77,18 @@ void atom_table_write_bytes(struct AtomTable *table, atom_ref_t atom, size_t buf void atom_table_write_cstring( struct AtomTable *table, atom_ref_t atom, size_t buf_len, char *outbuf); +/** + * @brief Allocate a new C string with malloc with the representation of + * an atom + * + * @param table atom table + * @param atom_index index of the atom to get the representation of + * @param suffix suffix to append to atom name or NULL of none + * @return a newly allocated string with the representation of the atom or + * NULL if allocation failed or atom index doesn't exist + */ +char *atom_table_atom_to_new_cstring(struct AtomTable *table, atom_index_t atom_index, const char *suffix); + #ifdef __cplusplus } #endif diff --git a/src/libAtomVM/atomshashtable.c b/src/libAtomVM/atomshashtable.c deleted file mode 100644 index d30600b89..000000000 --- a/src/libAtomVM/atomshashtable.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of AtomVM. - * - * Copyright 2018 Davide Bettio - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later - */ - -#include "atomshashtable.h" - -#include "smp.h" -#include "utils.h" - -#include -#include - -#ifndef AVM_NO_SMP -#define SMP_RDLOCK(htable) smp_rwlock_rdlock(htable->lock) -#define SMP_WRLOCK(htable) smp_rwlock_wrlock(htable->lock) -#define SMP_UNLOCK(htable) smp_rwlock_unlock(htable->lock) -#else -#define SMP_RDLOCK(htable) -#define SMP_WRLOCK(htable) -#define SMP_UNLOCK(htable) -#endif - -#define DEFAULT_SIZE 8 - -struct HNode -{ - struct HNode *next; - AtomString key; - unsigned long value; -}; - -static unsigned long sdbm_hash(const unsigned char *str, int len) -{ - unsigned long hash = 0; - int c; - - for (int i = 0; i < len; i++) { - c = *str++; - hash = c + (hash << 6) + (hash << 16) - hash; - } - - return hash; -} - -struct AtomsHashTable *atomshashtable_new() -{ - struct AtomsHashTable *htable = malloc(sizeof(struct AtomsHashTable)); - if (IS_NULL_PTR(htable)) { - return NULL; - } - htable->buckets = calloc(DEFAULT_SIZE, sizeof(struct HNode *)); - if (IS_NULL_PTR(htable->buckets)) { - free(htable); - return NULL; - } - - htable->count = 0; - htable->capacity = DEFAULT_SIZE; - -#ifndef AVM_NO_SMP - htable->lock = smp_rwlock_create(); -#endif - - return htable; -} - -int atomshashtable_insert(struct AtomsHashTable *hash_table, AtomString string, unsigned long value) -{ - int alen = atom_string_len(string); - - unsigned long hash = sdbm_hash(string, alen); - SMP_WRLOCK(hash_table); - long index = hash % hash_table->capacity; - - struct HNode *node = hash_table->buckets[index]; - if (node) { - while (1) { - if (atom_are_equals(string, node->key)) { - node->value = value; - SMP_UNLOCK(hash_table); - return 1; - } - - if (node->next) { - node = node->next; - } else { - break; - } - } - } - - struct HNode *new_node = malloc(sizeof(struct HNode)); - if (IS_NULL_PTR(new_node)) { - SMP_UNLOCK(hash_table); - return 0; - } - new_node->next = NULL; - new_node->key = string; - new_node->value = value; - - if (node) { - node->next = new_node; - } else { - hash_table->buckets[index] = new_node; - } - - hash_table->count++; - SMP_UNLOCK(hash_table); - return 1; -} - -unsigned long atomshashtable_get_value(const struct AtomsHashTable *hash_table, const AtomString string, unsigned long default_value) -{ - unsigned long hash = sdbm_hash(string, atom_string_len(string)); - SMP_RDLOCK(hash_table); - long index = hash % hash_table->capacity; - - const struct HNode *node = hash_table->buckets[index]; - while (node) { - if (atom_are_equals(string, node->key)) { - unsigned long result = node->value; - SMP_UNLOCK(hash_table); - return result; - } - - node = node->next; - } - - SMP_UNLOCK(hash_table); - return default_value; -} - -int atomshashtable_has_key(const struct AtomsHashTable *hash_table, const AtomString string) -{ - unsigned long hash = sdbm_hash(string, atom_string_len(string)); - SMP_RDLOCK(hash_table); - long index = hash % hash_table->capacity; - - const struct HNode *node = hash_table->buckets[index]; - while (node) { - if (atom_are_equals(string, node->key)) { - SMP_UNLOCK(hash_table); - return 1; - } - - node = node->next; - } - - SMP_UNLOCK(hash_table); - return 0; -} diff --git a/src/libAtomVM/atomshashtable.h b/src/libAtomVM/atomshashtable.h deleted file mode 100644 index 8ca472274..000000000 --- a/src/libAtomVM/atomshashtable.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of AtomVM. - * - * Copyright 2018 Davide Bettio - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later - */ - -#ifndef _ATOMSHASHTABLE_H_ -#define _ATOMSHASHTABLE_H_ - -#include "atom.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef AVM_NO_SMP -#ifndef TYPEDEF_RWLOCK -#define TYPEDEF_RWLOCK -typedef struct RWLock RWLock; -#endif -#endif - -struct AtomsHashTable -{ - int capacity; - int count; -#ifndef AVM_NO_SMP - RWLock *lock; -#endif - struct HNode **buckets; -}; - -struct AtomsHashTable *atomshashtable_new(); -int atomshashtable_insert(struct AtomsHashTable *hash_table, AtomString string, unsigned long value); -unsigned long atomshashtable_get_value(const struct AtomsHashTable *hash_table, AtomString string, unsigned long default_value); -int atomshashtable_has_key(const struct AtomsHashTable *hash_table, AtomString string); - -#define TO_ATOMSHASHTABLE_VALUE(value) ((unsigned long) (value)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index 0320f576a..be09e3c0b 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -25,7 +25,6 @@ #include "globalcontext.h" #include "atom_table.h" -#include "atomshashtable.h" #include "avmpack.h" #include "context.h" #include "defaultatoms.h" @@ -98,7 +97,7 @@ GlobalContext *globalcontext_new() glb->modules_by_index = NULL; glb->loaded_modules_count = 0; - glb->modules_table = atomshashtable_new(); + glb->modules_table = valueshashtable_new(); if (IS_NULL_PTR(glb->modules_table)) { atom_table_destroy(glb->atom_table); free(glb); @@ -637,9 +636,9 @@ term globalcontext_existing_term_from_atom_string(GlobalContext *glb, AtomString int globalcontext_insert_module(GlobalContext *global, Module *module) { + term module_name = module_get_name(module); SMP_RWLOCK_WRLOCK(global->modules_lock); - AtomString module_name_atom = module_get_atom_string_by_id(module, 1, global); - if (!atomshashtable_insert(global->modules_table, module_name_atom, TO_ATOMSHASHTABLE_VALUE(module))) { + if (!valueshashtable_insert(global->modules_table, term_to_atom_index(module_name), TO_VALUESHASHTABLE_VALUE(module))) { SMP_RWLOCK_UNLOCK(global->modules_lock); return -1; } @@ -692,18 +691,15 @@ Module *globalcontext_load_module_from_avm(GlobalContext *global, const char *mo return module_new_from_iff_binary(global, beam_module, beam_module_size); } -Module *globalcontext_get_module(GlobalContext *global, AtomString module_name_atom) +Module *globalcontext_get_module(GlobalContext *global, atom_index_t module_name_atom) { - Module *found_module = (Module *) atomshashtable_get_value(global->modules_table, module_name_atom, (unsigned long) NULL); + Module *found_module = (Module *) valueshashtable_get_value(global->modules_table, module_name_atom, TO_VALUESHASHTABLE_VALUE(NULL)); if (!found_module) { - char *module_name = malloc(256 + 5); + char *module_name = atom_table_atom_to_new_cstring(global->atom_table, module_name_atom, ".beam"); if (IS_NULL_PTR(module_name)) { return NULL; } - - atom_string_to_c(module_name_atom, module_name, 256); - strcat(module_name, ".beam"); Module *loaded_module = globalcontext_load_module_from_avm(global, module_name); if (IS_NULL_PTR(loaded_module)) { // Platform may implement sys_load_module_from_file diff --git a/src/libAtomVM/globalcontext.h b/src/libAtomVM/globalcontext.h index 96d226315..425448630 100644 --- a/src/libAtomVM/globalcontext.h +++ b/src/libAtomVM/globalcontext.h @@ -40,6 +40,7 @@ #include "synclist.h" #include "term.h" #include "timer_list.h" +#include "valueshashtable.h" #ifdef __cplusplus extern "C" { @@ -117,7 +118,7 @@ struct GlobalContext int32_t last_process_id; struct AtomTable *atom_table; - struct AtomsHashTable *modules_table; + struct ValuesHashTable *modules_table; #ifndef AVM_NO_SMP RWLock *modules_lock; @@ -510,7 +511,7 @@ Module *globalcontext_get_module_by_index(GlobalContext *global, int index); * @param module_name_atom the module name. * @returns a pointer to a Module struct. */ -Module *globalcontext_get_module(GlobalContext *global, AtomString module_name_atom); +Module *globalcontext_get_module(GlobalContext *global, atom_index_t module_name_atom); /** * @brief Load a given module from registered AVM packs diff --git a/src/libAtomVM/module.c b/src/libAtomVM/module.c index 62a517cbc..b7bd64e9c 100644 --- a/src/libAtomVM/module.c +++ b/src/libAtomVM/module.c @@ -469,7 +469,7 @@ const struct ExportedFunction *module_resolve_function0(Module *mod, int import_ AtomString function_name_atom = atom_table_get_atom_string(glb->atom_table, unresolved->function_atom_index); int arity = unresolved->arity; - Module *found_module = globalcontext_get_module(glb, module_name_atom); + Module *found_module = globalcontext_get_module(glb, unresolved->module_atom_index); if (LIKELY(found_module != NULL)) { int exported_label = module_search_exported_function(found_module, function_name_atom, arity, glb); diff --git a/src/libAtomVM/module.h b/src/libAtomVM/module.h index 57185c724..15e380296 100644 --- a/src/libAtomVM/module.h +++ b/src/libAtomVM/module.h @@ -33,12 +33,10 @@ #include "atom.h" #include "atom_table.h" -#include "atomshashtable.h" #include "context.h" #include "exportedfunction.h" #include "globalcontext.h" #include "term.h" -#include "valueshashtable.h" #ifdef __cplusplus extern "C" { diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index fef03bbd7..70594b9e6 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -1445,10 +1445,9 @@ term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) Context *new_ctx = context_new(ctx->global); - AtomString module_string = globalcontext_atomstring_from_term(ctx->global, argv[0]); AtomString function_string = globalcontext_atomstring_from_term(ctx->global, argv[1]); - Module *found_module = globalcontext_get_module(ctx->global, module_string); + Module *found_module = globalcontext_get_module(ctx->global, term_to_atom_index(module_term)); if (UNLIKELY(!found_module)) { return UNDEFINED_ATOM; } @@ -3886,7 +3885,7 @@ static term nif_erlang_function_exported(Context *ctx, int argc, term argv[]) return TRUE_ATOM; } - Module *target_module = globalcontext_get_module(ctx->global, module_name); + Module *target_module = globalcontext_get_module(ctx->global, module_name_ix); if (IS_NULL_PTR(target_module)) { return FALSE_ATOM; } @@ -4411,8 +4410,7 @@ static term nif_erlang_get_module_info(Context *ctx, int argc, term argv[]) VALIDATE_VALUE(argv[1], term_is_atom); } term module = argv[0]; - AtomString module_name = globalcontext_atomstring_from_term(ctx->global, module); - Module *target_module = globalcontext_get_module(ctx->global, module_name); + Module *target_module = globalcontext_get_module(ctx->global, term_to_atom_index(module)); if (IS_NULL_PTR(target_module)) { RAISE_ERROR(BADARG_ATOM); } @@ -5237,8 +5235,13 @@ static void *nif_code_all_available_fold(void *accum, const void *section_ptr, u char atom_str[module_name_len + 1]; atom_str[0] = module_name_len; memcpy(atom_str + 1, section_name, module_name_len); - Module *loaded_module = globalcontext_get_module(acc->ctx->global, (AtomString) &atom_str); - loaded = loaded_module != NULL; + term module_name_atom = globalcontext_insert_atom_maybe_copy(acc->ctx->global, (AtomString) atom_str, true); + if (UNLIKELY(term_is_invalid_term(module_name_atom))) { + loaded = false; + } else { + Module *loaded_module = globalcontext_get_module(acc->ctx->global, term_to_atom_index(module_name_atom)); + loaded = loaded_module != NULL; + } } else { loaded = false; } @@ -5414,8 +5417,7 @@ static term nif_code_ensure_loaded(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - AtomString module_string = globalcontext_atomstring_from_term(ctx->global, module_atom); - Module *found_module = globalcontext_get_module(ctx->global, module_string); + Module *found_module = globalcontext_get_module(ctx->global, term_to_atom_index(module_atom)); if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index 5762d8c65..eb82e4dcf 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -1242,7 +1242,7 @@ static void destroy_extended_registers(Context *ctx, unsigned int live) } \ continue; \ } else { \ - fun_module = globalcontext_get_module(ctx->global, module_name); \ + fun_module = globalcontext_get_module(ctx->global, term_to_atom_index(module)); \ if (IS_NULL_PTR(fun_module)) { \ SET_ERROR(UNDEF_ATOM); \ HANDLE_ERROR(); \ @@ -5416,7 +5416,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) x_regs[0] = native_return; } else { - Module *target_module = globalcontext_get_module(ctx->global, module_name); + Module *target_module = globalcontext_get_module(ctx->global, term_to_atom_index(module)); if (IS_NULL_PTR(target_module)) { pc = orig_pc; SET_ERROR(UNDEF_ATOM); @@ -5475,7 +5475,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DO_RETURN(); } else { - Module *target_module = globalcontext_get_module(ctx->global, module_name); + Module *target_module = globalcontext_get_module(ctx->global, term_to_atom_index(module)); if (IS_NULL_PTR(target_module)) { SET_ERROR(UNDEF_ATOM); HANDLE_ERROR(); diff --git a/src/libAtomVM/valueshashtable.c b/src/libAtomVM/valueshashtable.c index bd9cbea7e..4eb84994c 100644 --- a/src/libAtomVM/valueshashtable.c +++ b/src/libAtomVM/valueshashtable.c @@ -30,9 +30,9 @@ #define SMP_WRLOCK(htable) smp_rwlock_wrlock(htable->lock) #define SMP_UNLOCK(htable) smp_rwlock_unlock(htable->lock) #else -#define SMP_RDLOCK(htable) -#define SMP_WRLOCK(htable) -#define SMP_UNLOCK(htable) +#define SMP_RDLOCK(htable) UNUSED(htable) +#define SMP_WRLOCK(htable) UNUSED(htable) +#define SMP_UNLOCK(htable) UNUSED(htable) #endif #define DEFAULT_SIZE 8 @@ -40,8 +40,8 @@ struct HNode { struct HNode *next; - unsigned long key; - unsigned long value; + uintptr_t key; + uintptr_t value; }; struct ValuesHashTable *valueshashtable_new() @@ -65,10 +65,10 @@ struct ValuesHashTable *valueshashtable_new() return htable; } -int valueshashtable_insert(struct ValuesHashTable *hash_table, unsigned long key, unsigned long value) +int valueshashtable_insert(struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t value) { SMP_WRLOCK(hash_table); - long index = key % hash_table->capacity; + size_t index = key % hash_table->capacity; struct HNode *node = hash_table->buckets[index]; if (node) { @@ -107,15 +107,15 @@ int valueshashtable_insert(struct ValuesHashTable *hash_table, unsigned long key return 1; } -unsigned long valueshashtable_get_value(const struct ValuesHashTable *hash_table, unsigned long key, unsigned long default_value) +uintptr_t valueshashtable_get_value(const struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t default_value) { SMP_RDLOCK(hash_table); - long index = key % hash_table->capacity; + size_t index = key % hash_table->capacity; const struct HNode *node = hash_table->buckets[index]; while (node) { if (node->key == key) { - unsigned long result = node->value; + uintptr_t result = node->value; SMP_UNLOCK(hash_table); return result; } @@ -127,10 +127,10 @@ unsigned long valueshashtable_get_value(const struct ValuesHashTable *hash_table return default_value; } -int valueshashtable_has_key(const struct ValuesHashTable *hash_table, unsigned long key) +int valueshashtable_has_key(const struct ValuesHashTable *hash_table, uintptr_t key) { SMP_RDLOCK(hash_table); - long index = key % hash_table->capacity; + size_t index = key % hash_table->capacity; const struct HNode *node = hash_table->buckets[index]; while (node) { diff --git a/src/libAtomVM/valueshashtable.h b/src/libAtomVM/valueshashtable.h index 878434678..5f0c8d17a 100644 --- a/src/libAtomVM/valueshashtable.h +++ b/src/libAtomVM/valueshashtable.h @@ -21,10 +21,15 @@ #ifndef _VALUESHASHTABLE_H_ #define _VALUESHASHTABLE_H_ +#include +#include + #ifdef __cplusplus extern "C" { #endif +#define TO_VALUESHASHTABLE_VALUE(value) ((uintptr_t) (value)) + #ifndef AVM_NO_SMP #ifndef TYPEDEF_RWLOCK #define TYPEDEF_RWLOCK @@ -34,8 +39,8 @@ typedef struct RWLock RWLock; struct ValuesHashTable { - int capacity; - int count; + size_t capacity; + size_t count; #ifndef AVM_NO_SMP RWLock *lock; #endif @@ -43,9 +48,9 @@ struct ValuesHashTable }; struct ValuesHashTable *valueshashtable_new(); -int valueshashtable_insert(struct ValuesHashTable *hash_table, unsigned long key, unsigned long value); -unsigned long valueshashtable_get_value(const struct ValuesHashTable *hash_table, unsigned long key, unsigned long default_value); -int valueshashtable_has_key(const struct ValuesHashTable *hash_table, unsigned long key); +int valueshashtable_insert(struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t value); +uintptr_t valueshashtable_get_value(const struct ValuesHashTable *hash_table, uintptr_t key, uintptr_t default_value); +int valueshashtable_has_key(const struct ValuesHashTable *hash_table, uintptr_t key); #ifdef __cplusplus } diff --git a/tests/test-structs.c b/tests/test-structs.c index 95462f6a8..3fed8fd72 100644 --- a/tests/test-structs.c +++ b/tests/test-structs.c @@ -21,7 +21,6 @@ #include #include -#include "atomshashtable.h" #include "atom_table.h" #include "utils.h" #include "valueshashtable.h" @@ -160,99 +159,6 @@ static const char *const bounded_free_atom = "\xC" "bounded_free"; static const char *const minimum_atom = "\x7" "minimum"; static const char *const fibonacci_atom = "\x9" "fibonacci"; -void test_atomshashtable() -{ - char atom_hello[] = {5, 'h', 'e', 'l', 'l', 'o'}; - char atom_ciao[] = {4, 'c', 'i', 'a', 'o'}; - char atom_a[] = {1, 'a'}; - char atom_b[] = {1, 'b'}; - char atom_c[] = {1, 'c'}; - char atom_d[] = {1, 'd'}; - char atom_e[] = {1, 'e'}; - char atom_f[] = {1, 'f'}; - char atom_0[] = {1, '0'}; - char atom_1[] = {1, '1'}; - char atom_2[] = {1, '2'}; - char atom_3[] = {1, '3'}; - char atom_4[] = {1, '4'}; - char atom_5[] = {1, '5'}; - char atom_6[] = {1, '6'}; - char atom_7[] = {1, '7'}; - char atom_8[] = {1, '8'}; - char atom_9[] = {1, '9'}; - - struct AtomsHashTable *htable = atomshashtable_new(); - - assert(atomshashtable_insert(htable, atom_hello, 0xABCD1234) == 1); - assert(atomshashtable_get_value(htable, atom_hello, 0xCAFECAFE) == 0xABCD1234); - assert(atomshashtable_get_value(htable, atom_ciao, 0xCAFECAFE) == 0xCAFECAFE); - assert(atomshashtable_has_key(htable, atom_hello) == 1); - assert(atomshashtable_has_key(htable, atom_ciao) == 0); - - assert(atomshashtable_insert(htable, atom_hello, 0x11112222) == 1); - assert(atomshashtable_get_value(htable, atom_hello, 0xCAFECAFE) == 0x11112222); - assert(atomshashtable_get_value(htable, atom_ciao, 0xCAFECAFE) == 0xCAFECAFE); - - assert(atomshashtable_insert(htable, atom_ciao, 0x99887766) == 1); - assert(atomshashtable_get_value(htable, atom_ciao, 0xCAFECAFE) == 0x99887766); - assert(atomshashtable_get_value(htable, atom_hello, 0xCAFECAFE) == 0x11112222); - - assert(atomshashtable_insert(htable, atom_a, 0xA) == 1); - assert(atomshashtable_insert(htable, atom_b, 0xB) == 1); - assert(atomshashtable_insert(htable, atom_c, 0xC) == 1); - assert(atomshashtable_insert(htable, atom_d, 0xD) == 1); - assert(atomshashtable_insert(htable, atom_e, 0xE) == 1); - assert(atomshashtable_insert(htable, atom_f, 0xF) == 1); - assert(atomshashtable_insert(htable, atom_0, 0x0) == 1); - assert(atomshashtable_insert(htable, atom_1, 0x1) == 1); - assert(atomshashtable_insert(htable, atom_2, 0x2) == 1); - assert(atomshashtable_insert(htable, atom_3, 0x3) == 1); - assert(atomshashtable_insert(htable, atom_4, 0x4) == 1); - assert(atomshashtable_insert(htable, atom_5, 0x5) == 1); - assert(atomshashtable_insert(htable, atom_6, 0x6) == 1); - assert(atomshashtable_insert(htable, atom_7, 0x7) == 1); - assert(atomshashtable_insert(htable, atom_8, 0x8) == 1); - assert(atomshashtable_insert(htable, atom_9, 0x9) == 1); - - assert(atomshashtable_get_value(htable, atom_hello, 0xCAFECAFE) == 0x11112222); - assert(atomshashtable_get_value(htable, atom_ciao, 0xCAFECAFE) == 0x99887766); - assert(atomshashtable_get_value(htable, atom_a, 0xCAFEBABE) == 0xA); - assert(atomshashtable_get_value(htable, atom_b, 0xCAFEBABE) == 0xB); - assert(atomshashtable_get_value(htable, atom_c, 0xCAFEBABE) == 0xC); - assert(atomshashtable_get_value(htable, atom_d, 0xCAFEBABE) == 0xD); - assert(atomshashtable_get_value(htable, atom_e, 0xCAFEBABE) == 0xE); - assert(atomshashtable_get_value(htable, atom_f, 0xCAFEBABE) == 0xF); - assert(atomshashtable_get_value(htable, atom_0, 0xCAFEBABE) == 0x0); - assert(atomshashtable_get_value(htable, atom_1, 0xCAFEBABE) == 0x1); - assert(atomshashtable_get_value(htable, atom_2, 0xCAFEBABE) == 0x2); - assert(atomshashtable_get_value(htable, atom_3, 0xCAFEBABE) == 0x3); - assert(atomshashtable_get_value(htable, atom_4, 0xCAFEBABE) == 0x4); - assert(atomshashtable_get_value(htable, atom_5, 0xCAFEBABE) == 0x5); - assert(atomshashtable_get_value(htable, atom_6, 0xCAFEBABE) == 0x6); - assert(atomshashtable_get_value(htable, atom_7, 0xCAFEBABE) == 0x7); - assert(atomshashtable_get_value(htable, atom_8, 0xCAFEBABE) == 0x8); - assert(atomshashtable_get_value(htable, atom_9, 0xCAFEBABE) == 0x9); - - assert(atomshashtable_has_key(htable, atom_hello) == 1); - assert(atomshashtable_has_key(htable, atom_ciao) == 1); - assert(atomshashtable_has_key(htable, atom_a) == 1); - assert(atomshashtable_has_key(htable, atom_b) == 1); - assert(atomshashtable_has_key(htable, atom_c) == 1); - assert(atomshashtable_has_key(htable, atom_d) == 1); - assert(atomshashtable_has_key(htable, atom_e) == 1); - assert(atomshashtable_has_key(htable, atom_f) == 1); - assert(atomshashtable_has_key(htable, atom_0) == 1); - assert(atomshashtable_has_key(htable, atom_1) == 1); - assert(atomshashtable_has_key(htable, atom_2) == 1); - assert(atomshashtable_has_key(htable, atom_3) == 1); - assert(atomshashtable_has_key(htable, atom_4) == 1); - assert(atomshashtable_has_key(htable, atom_5) == 1); - assert(atomshashtable_has_key(htable, atom_6) == 1); - assert(atomshashtable_has_key(htable, atom_7) == 1); - assert(atomshashtable_has_key(htable, atom_8) == 1); - assert(atomshashtable_has_key(htable, atom_9) == 1); -} - void test_valueshashtable() { struct ValuesHashTable *htable = valueshashtable_new(); @@ -573,7 +479,6 @@ int main(int argc, char **argv) UNUSED(argc); UNUSED(argv); - test_atomshashtable(); test_valueshashtable(); test_atom_table(); From f260b376381edfac7cb3c32278c410c602ba86e9 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Thu, 20 Mar 2025 22:10:25 +0100 Subject: [PATCH 7/7] Allow atoms longer than 255 bytes Update atom_table API so it uses pointers to characters with a length, and reduce further usage of AtomString which represent shorter atoms Signed-off-by: Paul Guyot --- src/libAtomVM/atom_table.c | 212 +++++----------- src/libAtomVM/atom_table.h | 49 ++-- src/libAtomVM/bif.c | 65 +++-- src/libAtomVM/ets_hashtable.c | 5 +- src/libAtomVM/exportedfunction.h | 4 +- src/libAtomVM/externalterm.c | 61 +++-- src/libAtomVM/globalcontext.c | 38 ++- src/libAtomVM/globalcontext.h | 20 +- src/libAtomVM/interop.c | 20 +- src/libAtomVM/module.c | 47 ++-- src/libAtomVM/module.h | 24 +- src/libAtomVM/nifs.c | 94 +++---- src/libAtomVM/opcodesswitch.h | 36 +-- src/libAtomVM/stacktrace.c | 23 +- src/libAtomVM/term.c | 66 ++--- src/libAtomVM/term.h | 3 +- src/platforms/emscripten/src/main.c | 2 +- .../esp32/components/avm_builtins/nvs_nif.c | 9 +- src/platforms/generic_unix/main.c | 2 +- tests/erlang_tests/test_binary_to_atom.erl | 28 +++ tests/erlang_tests/test_binary_to_term.erl | 60 ++++- tests/erlang_tests/test_list_to_atom.erl | 30 ++- tests/test-structs.c | 235 +++++++++--------- 23 files changed, 546 insertions(+), 587 deletions(-) diff --git a/src/libAtomVM/atom_table.c b/src/libAtomVM/atom_table.c index f97a17c6c..addfd27ed 100644 --- a/src/libAtomVM/atom_table.c +++ b/src/libAtomVM/atom_table.c @@ -42,6 +42,7 @@ #define DEFAULT_SIZE 8 #define CAPACITY_INCREASE 8 +#define MAX_ATOM_LEN ((1 << 12) - 1) #define ATOM_TABLE_THRESHOLD(capacity) (capacity + (capacity >> 2)) #define ATOM_TABLE_NEW_CAPACITY(new_count) (new_count + CAPACITY_INCREASE) @@ -49,8 +50,9 @@ struct HNode { struct HNode *next; - AtomString key; - atom_index_t index; + const uint8_t *key; + uint32_t index : 20; + uint32_t bytes_len : 10; }; struct HNodeGroup @@ -148,7 +150,7 @@ static struct HNodeGroup *new_node_group(struct AtomTable *table, int len) static unsigned long sdbm_hash(const unsigned char *str, int len) { - unsigned long hash = 0; + unsigned long hash = len; int c; for (int i = 0; i < len; i++) { @@ -160,11 +162,11 @@ static unsigned long sdbm_hash(const unsigned char *str, int len) } static inline struct HNode *get_node_from_bucket( - const struct AtomTable *hash_table, unsigned long bucket_index, AtomString string) + const struct AtomTable *hash_table, unsigned long bucket_index, const uint8_t *string, size_t string_len) { struct HNode *node = hash_table->buckets[bucket_index]; while (node) { - if (atom_are_equals(string, node->key)) { + if (node->bytes_len == string_len && memcmp(node->key, string, string_len) == 0) { return node; } @@ -175,17 +177,17 @@ static inline struct HNode *get_node_from_bucket( } static inline struct HNode *get_node_with_hash( - const struct AtomTable *hash_table, AtomString string, unsigned long hash) + const struct AtomTable *hash_table, const uint8_t *string, size_t string_len, unsigned long hash) { unsigned long bucket_index = hash % hash_table->capacity; - return get_node_from_bucket(hash_table, bucket_index, string); + return get_node_from_bucket(hash_table, bucket_index, string, string_len); } -static inline struct HNode *get_node(const struct AtomTable *hash_table, AtomString string) +static inline struct HNode *get_node(const struct AtomTable *hash_table, const uint8_t *string, size_t string_len) { - unsigned long hash = sdbm_hash(string, atom_string_len(string)); + unsigned long hash = sdbm_hash(string, string_len); - return get_node_with_hash(hash_table, string, hash); + return get_node_with_hash(hash_table, string, string_len, hash); } // TODO: this function needs use an efficient structure such as a skip list @@ -208,8 +210,9 @@ static struct HNode *get_node_using_index(struct AtomTable *table, atom_index_t return NULL; } -AtomString atom_table_get_atom_string(struct AtomTable *table, atom_index_t index) +const uint8_t *atom_table_get_atom_string(struct AtomTable *table, atom_index_t index, size_t *out_size) { + const uint8_t *result; SMP_RDLOCK(table); struct HNode *node = get_node_using_index(table, index); @@ -217,24 +220,37 @@ AtomString atom_table_get_atom_string(struct AtomTable *table, atom_index_t inde SMP_UNLOCK(table); return NULL; } - - AtomString found_key = node->key; + result = node->key; + *out_size = node->bytes_len; SMP_UNLOCK(table); - return found_key; + return result; } -int atom_table_cmp_using_atom_index(struct AtomTable *table, int t_atom_index, int other_atom_index) +bool atom_table_is_equal_to_atom_string(struct AtomTable *table, atom_index_t t_atom_index, AtomString string) { - AtomString t_atom_string = atom_table_get_atom_string(table, t_atom_index); + size_t t_atom_len; + const uint8_t *t_atom_data = atom_table_get_atom_string(table, t_atom_index, &t_atom_len); + if (IS_NULL_PTR(t_atom_data)) { + return false; + } - int t_atom_len = atom_string_len(t_atom_string); - const char *t_atom_data = (const char *) atom_string_data(t_atom_string); + return (t_atom_len == atom_string_len(string)) && (memcmp(t_atom_data, atom_string_data(string), t_atom_len) == 0); +} - AtomString other_atom_string = atom_table_get_atom_string(table, other_atom_index); +int atom_table_cmp_using_atom_index(struct AtomTable *table, atom_index_t t_atom_index, atom_index_t other_atom_index) +{ + size_t t_atom_len; + const uint8_t *t_atom_data = atom_table_get_atom_string(table, t_atom_index, &t_atom_len); + if (IS_NULL_PTR(t_atom_data)) { + return -1; + } - int other_atom_len = atom_string_len(other_atom_string); - const char *other_atom_data = (const char *) atom_string_data(other_atom_string); + size_t other_atom_len; + const uint8_t *other_atom_data = atom_table_get_atom_string(table, other_atom_index, &other_atom_len); + if (IS_NULL_PTR(other_atom_data)) { + return 1; + } int cmp_size = (t_atom_len > other_atom_len) ? other_atom_len : t_atom_len; @@ -267,73 +283,10 @@ atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, atom_index_t return node; } -char *atom_table_atom_to_new_cstring(struct AtomTable *table, atom_index_t atom_index, const char *suffix) -{ - AtomString atom_string = atom_table_get_atom_string(table, atom_index); - size_t atom_len = atom_string_len(atom_string); - const uint8_t *atom_data = atom_string_data(atom_string); - size_t suffix_len = 0; - if (suffix) { - suffix_len = strlen(suffix); - } - - char *result = malloc(atom_len + suffix_len + 1); - if (IS_NULL_PTR(result)) { - return NULL; - } - - memcpy(result, atom_data, atom_len); - if (suffix) { - memcpy(result + atom_len, suffix, suffix_len); - } - result[atom_len + suffix_len] = 0; - - return result; -} - -bool atom_table_is_atom_ref_ascii(struct AtomTable *table, atom_ref_t atom) +static inline void init_node(struct HNode *node, const uint8_t *atom_data, size_t atom_len, long index) { - SMP_RDLOCK(table); - - struct HNode *node = (struct HNode *) atom; - const uint8_t *data = atom_string_data(node->key); - size_t len = atom_string_len(node->key); - - bool result = unicode_buf_is_ascii(data, len); - - SMP_UNLOCK(table); - return result; -} - -void atom_table_write_bytes(struct AtomTable *table, atom_ref_t atom, size_t buf_len, void *outbuf) -{ - SMP_RDLOCK(table); - - struct HNode *node = (struct HNode *) atom; - size_t len = atom_string_len(node->key); - if (len > buf_len) { - len = buf_len; - } - - memcpy(outbuf, atom_string_data(node->key), len); - - SMP_UNLOCK(table); -} - -void atom_table_write_cstring( - struct AtomTable *table, atom_ref_t atom, size_t buf_len, char *outbuf) -{ - SMP_RDLOCK(table); - - struct HNode *node = (struct HNode *) atom; - atom_string_to_c(node->key, outbuf, buf_len); - - SMP_UNLOCK(table); -} - -static inline void init_node(struct HNode *node, AtomString atom, long index) -{ - node->key = atom; + node->key = atom_data; + node->bytes_len = atom_len; node->index = index; } @@ -346,14 +299,14 @@ static inline void insert_node_into_bucket( } static inline atom_index_t insert_node(struct AtomTable *table, struct HNodeGroup *node_group, - unsigned long bucket_index, AtomString string) + unsigned long bucket_index, const uint8_t *atom_data, size_t atom_len) { atom_index_t new_index = table->count; table->count++; struct HNode *node = &node_group->nodes[new_index - node_group->first_index]; table->last_node_group_avail--; - init_node(node, string, new_index); + init_node(node, atom_data, atom_len, new_index); insert_node_into_bucket(table, bucket_index, node); return new_index; @@ -383,9 +336,7 @@ static bool do_rehash(struct AtomTable *table, int new_capacity) for (int i = 0; i < group_count; i++) { struct HNode *node = &group->nodes[i]; - AtomString key = node->key; - - unsigned long hash = sdbm_hash(key, atom_string_len(key)); + unsigned long hash = sdbm_hash(node->key, node->bytes_len); unsigned long bucket_index = hash % table->capacity; insert_node_into_bucket(table, bucket_index, node); @@ -409,13 +360,13 @@ static inline bool maybe_rehash(struct AtomTable *table, int new_entries) return do_rehash(table, new_capacity); } -enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts, atom_index_t *result) +enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, const uint8_t *atom_data, size_t atom_len, enum AtomTableCopyOpt opts, atom_index_t *result) { - unsigned long hash = sdbm_hash(string, atom_string_len(string)); + unsigned long hash = sdbm_hash(atom_data, atom_len); SMP_WRLOCK(table); unsigned long bucket_index = hash % table->capacity; - struct HNode *node = get_node_from_bucket(table, bucket_index, string); + struct HNode *node = get_node_from_bucket(table, bucket_index, atom_data, atom_len); if (node) { SMP_UNLOCK(table); *result = node->index; @@ -435,23 +386,21 @@ enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, A } } - AtomString maybe_copied = string; if (opts & AtomTableCopyAtom) { - uint8_t len = *((uint8_t *) string); - uint8_t *buf = malloc(1 + len); + uint8_t *buf = malloc(atom_len); if (IS_NULL_PTR(buf)) { SMP_UNLOCK(table); return AtomTableEnsureAtomAllocFail; } - memcpy(buf, string, 1 + len); - maybe_copied = buf; + memcpy(buf, atom_data, atom_len); + atom_data = buf; } if (maybe_rehash(table, 1)) { bucket_index = hash % table->capacity; } - *result = insert_node(table, node_group, bucket_index, maybe_copied); + *result = insert_node(table, node_group, bucket_index, atom_data, atom_len); SMP_UNLOCK(table); return AtomTableEnsureAtomOk; @@ -478,7 +427,7 @@ static inline int read_encoded_len(const uint8_t **len_bytes) // -1 is not a valid atom index as we're limited to 2^20 #define ATOM_TABLE_NOT_FOUND_MARKER ((atom_index_t) -1) -enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, +enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, size_t count, atom_index_t *translate_table, enum EnsureAtomsOpt opt) { bool is_long_format = (opt & EnsureLongEncoding) != 0; @@ -489,35 +438,22 @@ enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const uint8_t *current_atom = atoms; - for (int i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { struct HNode *node; + int atom_len; if (is_long_format) { - int atom_len = read_encoded_len(¤t_atom); - if (UNLIKELY(atom_len < 0)) { + atom_len = read_encoded_len(¤t_atom); + if (UNLIKELY(atom_len < 0 || atom_len > MAX_ATOM_LEN)) { fprintf(stderr, "Found invalid atom len."); SMP_UNLOCK(table); return AtomTableEnsureAtomInvalidLen; - } else if (UNLIKELY(atom_len > 255)) { - fprintf(stderr, - "Unsupported atom length %i bytes.\n" - "Unlike OTP >= 28, AtomVM supports a maximum of 255 bytes" - "regardeless the number of codepoints.\n" - "If you are seeing this error please open an issue on GitHub:\n" - "https://github.com/atomvm/AtomVM/issues\n", - atom_len); - SMP_UNLOCK(table); - return AtomTableEnsureAtomInvalidLen; } - char tmp_old_fmt[256]; - tmp_old_fmt[0] = atom_len; - memcpy(tmp_old_fmt + 1, current_atom, atom_len); - node = get_node(table, tmp_old_fmt); - current_atom += atom_len; } else { - node = get_node(table, current_atom); - uint8_t atom_len = current_atom[0]; - current_atom += 1 + atom_len; + atom_len = current_atom[0]; + current_atom++; } + node = get_node(table, current_atom, atom_len); + current_atom += atom_len; if (node) { translate_table[i] = node->index; @@ -532,18 +468,14 @@ enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, current_atom = atoms; int remaining_atoms = new_atoms_count; struct HNodeGroup *node_group = table->last_node_group; - for (int i = 0; i < count; i++) { - - const uint8_t *to_be_copied = NULL; - const uint8_t *next_atom = current_atom; - uint8_t atom_len; + for (size_t i = 0; i < count; i++) { + size_t atom_len; if (is_long_format) { - atom_len = read_encoded_len(&next_atom); - to_be_copied = next_atom; - next_atom += atom_len; + // Size was checked above + atom_len = (size_t) read_encoded_len(¤t_atom); } else { atom_len = current_atom[0]; - next_atom += 1 + atom_len; + current_atom++; } if (translate_table[i] == ATOM_TABLE_NOT_FOUND_MARKER) { @@ -555,28 +487,16 @@ enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, } } - if (is_long_format) { - uint8_t *atom_copy = malloc(atom_len + 1); - if (IS_NULL_PTR(atom_copy)) { - // we are not going to remove atoms that have already been added up to this one - SMP_UNLOCK(table); - return AtomTableEnsureAtomAllocFail; - } - atom_copy[0] = atom_len; - memcpy(atom_copy + 1, to_be_copied, atom_len); - current_atom = atom_copy; - } - unsigned long hash = sdbm_hash(current_atom, atom_len); unsigned long bucket_index = hash % table->capacity; - translate_table[i] = insert_node(table, node_group, bucket_index, current_atom); + translate_table[i] = insert_node(table, node_group, bucket_index, current_atom, atom_len); remaining_atoms--; if (remaining_atoms == 0) { break; } } - current_atom = next_atom; + current_atom += atom_len; } SMP_UNLOCK(table); diff --git a/src/libAtomVM/atom_table.h b/src/libAtomVM/atom_table.h index 0f4b496d8..33198e411 100644 --- a/src/libAtomVM/atom_table.h +++ b/src/libAtomVM/atom_table.h @@ -60,34 +60,53 @@ void atom_table_destroy(struct AtomTable *table); size_t atom_table_count(struct AtomTable *table); -enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts, atom_index_t *result) MUST_CHECK; +atom_index_t atom_table_get_index(struct AtomTable *table, AtomString string); +atom_index_t atom_table_get_index_from_cstring(struct AtomTable *table, const char *name); -// This function is deprecated and it will be removed. -// atom strings should be copied to caller owned buffers. -AtomString atom_table_get_atom_string(struct AtomTable *table, atom_index_t index); +enum AtomTableEnsureAtomResult atom_table_ensure_atom(struct AtomTable *table, const uint8_t *atom_data, size_t atom_len, enum AtomTableCopyOpt opts, atom_index_t *result) MUST_CHECK; -enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count, +enum AtomTableEnsureAtomResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, size_t count, atom_index_t *translate_table, enum EnsureAtomsOpt opts) MUST_CHECK; +bool atom_table_is_equal_to_atom_string( + struct AtomTable *table, atom_index_t t_atom_index, AtomString atom_string); int atom_table_cmp_using_atom_index( - struct AtomTable *table, int t_atom_index, int other_atom_index); + struct AtomTable *table, atom_index_t t_atom_index, atom_index_t other_atom_index); + atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, atom_index_t index, size_t *out_len); bool atom_table_is_atom_ref_ascii(struct AtomTable *table, atom_ref_t atom); -void atom_table_write_bytes(struct AtomTable *table, atom_ref_t atom, size_t buf_len, void *outbuf); -void atom_table_write_cstring( - struct AtomTable *table, atom_ref_t atom, size_t buf_len, char *outbuf); /** - * @brief Allocate a new C string with malloc with the representation of - * an atom + * @brief Get a pointer to the character data of a given atom. + * + * @details returned pointer is not null terminated * * @param table atom table * @param atom_index index of the atom to get the representation of - * @param suffix suffix to append to atom name or NULL of none - * @return a newly allocated string with the representation of the atom or - * NULL if allocation failed or atom index doesn't exist + * @param out_len on output, size of the character data + */ +const uint8_t *atom_table_get_atom_string(struct AtomTable *table, atom_index_t index, size_t *out_len); + +/** + * @brief Write module:function/arity to the supplied buffer. + * + * @details Write module:function/arity to the supplied buffer. This function will abort + * if the written module, function, and arity are longer than the supplied + * buffer size. + * @param buf the buffer to write into + * @param buf_size the amount of room in the buffer + * @param module the module name + * @param function the function name + * @param arity the function arity */ -char *atom_table_atom_to_new_cstring(struct AtomTable *table, atom_index_t atom_index, const char *suffix); +static inline void atom_table_write_mfa(struct AtomTable *table, char *buf, size_t buf_size, atom_index_t module, atom_index_t function, unsigned int arity) +{ + size_t module_name_len; + const uint8_t *module_name = atom_table_get_atom_string(table, module, &module_name_len); + size_t function_name_len; + const uint8_t *function_name = atom_table_get_atom_string(table, function, &function_name_len); + atom_write_mfa(buf, buf_size, module_name_len, module_name, function_name_len, function_name, arity); +} #ifdef __cplusplus } diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index 2fe4c651f..2aa965300 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -1727,35 +1727,29 @@ static term list_to_atom(Context *ctx, term a_list, bool create_new, term *error } int ok; - char *atom_string = interop_list_to_utf8_string(a_list, &ok); + avm_int_t len = term_list_length(a_list, &ok); if (UNLIKELY(!ok)) { - *error_reason = OUT_OF_MEMORY_ATOM; + *error_reason = BADARG_ATOM; return term_invalid_term(); } - int atom_string_len = strlen(atom_string); - if (UNLIKELY(atom_string_len > 255)) { - free(atom_string); + if (len > 255) { *error_reason = SYSTEM_LIMIT_ATOM; return term_invalid_term(); } - AtomString atom = malloc(atom_string_len + 1); - if (IS_NULL_PTR(atom)) { - free(atom_string); + char *atom_string = interop_list_to_utf8_string(a_list, &ok); + if (UNLIKELY(!ok)) { *error_reason = OUT_OF_MEMORY_ATOM; return term_invalid_term(); } - ((uint8_t *) atom)[0] = atom_string_len; - memcpy(((char *) atom) + 1, atom_string, atom_string_len); - free(atom_string); + size_t atom_string_len = strlen(atom_string); enum AtomTableCopyOpt atom_opts = AtomTableCopyAtom; if (!create_new) { atom_opts |= AtomTableAlreadyExisting; } atom_index_t global_atom_index; - enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts, &global_atom_index); - free((void *) atom); + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, (const uint8_t *) atom_string, atom_string_len, atom_opts, &global_atom_index); switch (ensure_result) { case AtomTableEnsureAtomNotFound: case AtomTableEnsureAtomInvalidLen: { @@ -1807,10 +1801,6 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new, const char *atom_string = term_binary_data(a_binary); size_t atom_string_len = term_binary_size(a_binary); - if (UNLIKELY(atom_string_len > 255)) { - *error_reason = SYSTEM_LIMIT_ATOM; - return term_invalid_term(); - } bool encode_latin1_to_utf8 = false; if (UNLIKELY((encoding == LATIN1_ATOM) @@ -1822,40 +1812,42 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new, return term_invalid_term(); } - AtomString atom; + const uint8_t *atom_data; + size_t atom_data_len; + uint8_t *buf = NULL; if (LIKELY(!encode_latin1_to_utf8)) { if (UNLIKELY(!unicode_is_valid_utf8_buf((const uint8_t *) atom_string, atom_string_len))) { *error_reason = BADARG_ATOM; return term_invalid_term(); } - atom = malloc(atom_string_len + 1); - if (IS_NULL_PTR(atom)) { - *error_reason = OUT_OF_MEMORY_ATOM; + size_t len = unicode_buf_utf8_len((const uint8_t *) atom_string, atom_string_len); + if (UNLIKELY(len > 255)) { + *error_reason = SYSTEM_LIMIT_ATOM; return term_invalid_term(); } - ((uint8_t *) atom)[0] = atom_string_len; - memcpy(((char *) atom) + 1, atom_string, atom_string_len); + + atom_data = (const uint8_t *) atom_string; + atom_data_len = atom_string_len; } else { + if (UNLIKELY(atom_string_len > 255)) { + *error_reason = SYSTEM_LIMIT_ATOM; + return term_invalid_term(); + } + // * 2 is the worst case size size_t buf_len = atom_string_len * 2; - atom = malloc(buf_len + 1); - if (IS_NULL_PTR(atom)) { + buf = malloc(buf_len); + if (IS_NULL_PTR(buf)) { *error_reason = OUT_OF_MEMORY_ATOM; return term_invalid_term(); } - uint8_t *atom_data = ((uint8_t *) atom) + 1; - size_t out_pos = 0; + atom_data = buf; + atom_data_len = 0; for (size_t i = 0; i < atom_string_len; i++) { size_t out_size; - bitstring_utf8_encode(((uint8_t) atom_string[i]), &atom_data[out_pos], &out_size); - out_pos += out_size; - } - if (out_pos > 255) { - free((void *) atom); - *error_reason = SYSTEM_LIMIT_ATOM; - return term_invalid_term(); + bitstring_utf8_encode(((uint8_t) atom_string[i]), &buf[atom_data_len], &out_size); + atom_data_len += out_size; } - ((uint8_t *) atom)[0] = out_pos; } enum AtomTableCopyOpt atom_opts = AtomTableCopyAtom; @@ -1863,8 +1855,7 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new, atom_opts |= AtomTableAlreadyExisting; } atom_index_t global_atom_index; - enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts, &global_atom_index); - free((void *) atom); + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, atom_data, atom_data_len, atom_opts, &global_atom_index); switch (ensure_result) { case AtomTableEnsureAtomNotFound: case AtomTableEnsureAtomInvalidLen: { diff --git a/src/libAtomVM/ets_hashtable.c b/src/libAtomVM/ets_hashtable.c index 2673dd523..f41cde1f1 100644 --- a/src/libAtomVM/ets_hashtable.c +++ b/src/libAtomVM/ets_hashtable.c @@ -242,9 +242,8 @@ bool ets_hashtable_remove(struct EtsHashTable *hash_table, term key, size_t keyp static uint32_t hash_atom(term t, int32_t h, GlobalContext *global) { - AtomString atom_str = (uint8_t *) globalcontext_atomstring_from_term(global, t); - size_t len = atom_string_len(atom_str); - const uint8_t *data = (const uint8_t *) atom_string_data(atom_str); + size_t len; + const uint8_t *data = atom_table_get_atom_string(global->atom_table, term_to_atom_index(t), &len); for (size_t i = 0; i < len; ++i) { h = h * LARGE_PRIME_ATOM + data[i]; } diff --git a/src/libAtomVM/exportedfunction.h b/src/libAtomVM/exportedfunction.h index 4da04dc88..d6d45ec9f 100644 --- a/src/libAtomVM/exportedfunction.h +++ b/src/libAtomVM/exportedfunction.h @@ -93,8 +93,8 @@ struct Nif struct UnresolvedFunctionCall { struct ExportedFunction base; - int module_atom_index; - int function_atom_index; + atom_index_t module_atom_index; + atom_index_t function_atom_index; int arity; }; diff --git a/src/libAtomVM/externalterm.c b/src/libAtomVM/externalterm.c index 91dab2daf..3a92ef5b5 100644 --- a/src/libAtomVM/externalterm.c +++ b/src/libAtomVM/externalterm.c @@ -51,6 +51,7 @@ #define SMALL_BIG_EXT 110 #define EXPORT_EXT 113 #define MAP_EXT 116 +#define ATOM_UTF8_EXT 118 #define SMALL_ATOM_UTF8_EXT 119 #define V4_PORT_EXT 120 #define INVALID_TERM_SIZE -1 @@ -248,16 +249,25 @@ static int serialize_term(uint8_t *buf, term t, GlobalContext *glb) return NEW_FLOAT_EXT_SIZE; } else if (term_is_atom(t)) { - int atom_index = term_to_atom_index(t); + atom_index_t atom_index = term_to_atom_index(t); size_t atom_len; - atom_ref_t atom_ref = atom_table_get_atom_ptr_and_len(glb->atom_table, atom_index, &atom_len); - if (!IS_NULL_PTR(buf)) { - buf[0] = SMALL_ATOM_UTF8_EXT; - buf[1] = atom_len; - atom_table_write_bytes(glb->atom_table, atom_ref, atom_len, buf + 2); + const uint8_t *atom_data = atom_table_get_atom_string(glb->atom_table, atom_index, &atom_len); + if (UNLIKELY(atom_len >= 256)) { + if (!IS_NULL_PTR(buf)) { + buf[0] = ATOM_UTF8_EXT; + buf[1] = atom_len >> 8; + buf[2] = atom_len & 0xFF; + memcpy(buf + 3, atom_data, atom_len); + } + return ATOM_EXT_BASE_SIZE + atom_len; + } else { + if (!IS_NULL_PTR(buf)) { + buf[0] = SMALL_ATOM_UTF8_EXT; + buf[1] = atom_len; + memcpy(buf + 2, atom_data, atom_len); + } + return SMALL_ATOM_EXT_BASE_SIZE + atom_len; } - return 2 + atom_len; - } else if (term_is_tuple(t)) { size_t arity = term_get_tuple_arity(t); size_t k; @@ -523,21 +533,19 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm return term_invalid_term(); } - const uint8_t *atom_chars = (const uint8_t *) (external_term_buf + 3); + const uint8_t *atom_chars = (const uint8_t *) (external_term_buf + ATOM_EXT_BASE_SIZE); term atom_term; if (LIKELY(unicode_buf_is_ascii(atom_chars, atom_len))) { - // there is a trick here: we are reusing LSB of len field as atom length atom_term = globalcontext_insert_atom_maybe_copy( - glb, (AtomString) (external_term_buf + 2), copy); + glb, atom_chars, atom_len, copy); } else { // need to re-encode latin1 to UTF-8 size_t required_buf_size = unicode_latin1_buf_size_as_utf8(atom_chars, atom_len); if (UNLIKELY(required_buf_size > 255)) { return term_invalid_term(); } - uint8_t *atom_buf = malloc(1 + required_buf_size); - atom_buf[0] = required_buf_size; - uint8_t *curr_codepoint = &atom_buf[1]; + uint8_t *atom_buf = malloc(required_buf_size); + uint8_t *curr_codepoint = atom_buf; for (int i = 0; i < atom_len; i++) { size_t codepoint_size; // latin1 encoding is always successful @@ -545,11 +553,11 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm curr_codepoint += codepoint_size; } atom_term - = globalcontext_insert_atom_maybe_copy(glb, (AtomString) atom_buf, true); + = globalcontext_insert_atom_maybe_copy(glb, atom_buf, required_buf_size, true); free(atom_buf); } - *eterm_size = 3 + atom_len; + *eterm_size = ATOM_EXT_BASE_SIZE + atom_len; return atom_term; } @@ -695,17 +703,29 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm return map; } + case ATOM_UTF8_EXT: { + uint16_t atom_len = READ_16_UNALIGNED(external_term_buf + 1); + const uint8_t *atom_chars = external_term_buf + ATOM_EXT_BASE_SIZE; + + if (UNLIKELY(!unicode_is_valid_utf8_buf((const uint8_t *) atom_chars, atom_len))) { + return term_invalid_term(); + } + + term atom_term = globalcontext_insert_atom_maybe_copy(glb, atom_chars, atom_len, copy); + *eterm_size = ATOM_EXT_BASE_SIZE + atom_len; + return atom_term; + } + case SMALL_ATOM_UTF8_EXT: { uint8_t atom_len = *(external_term_buf + 1); - const uint8_t *atom_chars = external_term_buf + 2; + const uint8_t *atom_chars = external_term_buf + SMALL_ATOM_EXT_BASE_SIZE; if (UNLIKELY(!unicode_is_valid_utf8_buf((const uint8_t *) atom_chars, atom_len))) { return term_invalid_term(); } - // AtomString first byte is the atom length - term atom_term = globalcontext_insert_atom_maybe_copy(glb, (AtomString) (external_term_buf + 1), copy); - *eterm_size = 2 + atom_len; + term atom_term = globalcontext_insert_atom_maybe_copy(glb, atom_chars, atom_len, copy); + *eterm_size = SMALL_ATOM_EXT_BASE_SIZE + atom_len; return atom_term; } @@ -853,6 +873,7 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini return term_boxed_integer_size(value); } + case ATOM_UTF8_EXT: case ATOM_EXT: { if (UNLIKELY(remaining < ATOM_EXT_BASE_SIZE)) { return INVALID_TERM_SIZE; diff --git a/src/libAtomVM/globalcontext.c b/src/libAtomVM/globalcontext.c index be09e3c0b..38d9ea858 100644 --- a/src/libAtomVM/globalcontext.c +++ b/src/libAtomVM/globalcontext.c @@ -605,29 +605,14 @@ term globalcontext_get_registered_name_process(GlobalContext *glb, int local_pro bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, atom_index_t atom_index_a, AtomString atom_string_b) { - AtomString atom_string_a; - atom_string_a = atom_table_get_atom_string(glb->atom_table, atom_index_a); - return atom_are_equals(atom_string_a, atom_string_b); -} - -AtomString globalcontext_atomstring_from_term(GlobalContext *glb, term t) -{ - if (!term_is_atom(t)) { - AVM_ABORT(); - } - unsigned long atom_index = term_to_atom_index(t); - AtomString str = atom_table_get_atom_string(glb->atom_table, atom_index); - if (IS_NULL_PTR(str)) { - return NULL; - } - return str; + return atom_table_is_equal_to_atom_string(glb->atom_table, atom_index_a, atom_string_b); } term globalcontext_existing_term_from_atom_string(GlobalContext *glb, AtomString atom_string) { atom_index_t global_atom_index; enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom( - glb->atom_table, atom_string, AtomTableAlreadyExisting, &global_atom_index); + glb->atom_table, atom_string_data(atom_string), atom_string_len(atom_string), AtomTableAlreadyExisting, &global_atom_index); if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { return term_invalid_term(); } @@ -696,25 +681,30 @@ Module *globalcontext_get_module(GlobalContext *global, atom_index_t module_name Module *found_module = (Module *) valueshashtable_get_value(global->modules_table, module_name_atom, TO_VALUESHASHTABLE_VALUE(NULL)); if (!found_module) { - char *module_name = atom_table_atom_to_new_cstring(global->atom_table, module_name_atom, ".beam"); - if (IS_NULL_PTR(module_name)) { + size_t module_name_len; + const uint8_t *module_name = atom_table_get_atom_string(global->atom_table, module_name_atom, &module_name_len); + + char *module_file_name = malloc(module_name_len + 6); + if (IS_NULL_PTR(module_file_name)) { return NULL; } - Module *loaded_module = globalcontext_load_module_from_avm(global, module_name); + memcpy(module_file_name, module_name, module_name_len); + memcpy(module_file_name + module_name_len, ".beam", 6); + Module *loaded_module = globalcontext_load_module_from_avm(global, module_file_name); if (IS_NULL_PTR(loaded_module)) { // Platform may implement sys_load_module_from_file - loaded_module = sys_load_module_from_file(global, module_name); + loaded_module = sys_load_module_from_file(global, module_file_name); } if (UNLIKELY(!loaded_module || (globalcontext_insert_module(global, loaded_module) < 0))) { - fprintf(stderr, "Failed load module: %s\n", module_name); - free(module_name); + fprintf(stderr, "Failed load module: %s\n", module_file_name); + free(module_file_name); if (loaded_module) { module_destroy(loaded_module); } return NULL; } - free(module_name); + free(module_file_name); return loaded_module; } diff --git a/src/libAtomVM/globalcontext.h b/src/libAtomVM/globalcontext.h index 425448630..00113be93 100644 --- a/src/libAtomVM/globalcontext.h +++ b/src/libAtomVM/globalcontext.h @@ -399,11 +399,11 @@ void globalcontext_maybe_unregister_process_id(GlobalContext *glb, int process_i * assumes "ownership" of the allocated memory. * @returns newly added atom id or term_invalid_term() in case of failure. */ -static inline term globalcontext_insert_atom_maybe_copy(GlobalContext *glb, AtomString atom_string, bool copy) +static inline term globalcontext_insert_atom_maybe_copy(GlobalContext *glb, const uint8_t *atom_data, size_t atom_len, bool copy) { atom_index_t global_atom_index; enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom( - glb->atom_table, atom_string, copy ? AtomTableCopyAtom : AtomTableNoOpts, &global_atom_index); + glb->atom_table, atom_data, atom_len, copy ? AtomTableCopyAtom : AtomTableNoOpts, &global_atom_index); if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { return term_invalid_term(); } @@ -452,23 +452,9 @@ static inline bool globalcontext_is_term_equal_to_atom_string(GlobalContext *glo */ static inline term globalcontext_make_atom(GlobalContext *glb, AtomString atom_string) { - return globalcontext_insert_atom_maybe_copy(glb, atom_string, false); + return globalcontext_insert_atom_maybe_copy(glb, atom_string_data(atom_string), atom_string_len(atom_string), false); } -/** - * @brief Returns the AtomString value of a term. - * - * @details This function fetches the AtomString value of the atom associated - * with the supplied term. The input term must be an atom type. - * If no such atom is registered in the global table, this function - * returns NULL. The caller should NOT free the data associated with - * the returned value. - * @param glb the global context - * @param t the atom term - * @returns the AtomString associated with the supplied atom term. - */ -AtomString globalcontext_atomstring_from_term(GlobalContext *glb, term t); - /** * @brief Returns the term for an existing atom. * diff --git a/src/libAtomVM/interop.c b/src/libAtomVM/interop.c index b8ba2d1fc..2a5dbe6e2 100644 --- a/src/libAtomVM/interop.c +++ b/src/libAtomVM/interop.c @@ -198,19 +198,19 @@ char *interop_list_to_utf8_string(term list, int *ok) char *interop_atom_to_string(Context *ctx, term atom) { GlobalContext *glb = ctx->global; - - int atom_index = term_to_atom_index(atom); - - size_t len; - atom_ref_t atom_ref = atom_table_get_atom_ptr_and_len(glb->atom_table, atom_index, &len); - - char *str = malloc(len + 1); - if (IS_NULL_PTR(str)) { + size_t atom_len; + const uint8_t *atom_data = atom_table_get_atom_string(glb->atom_table, term_to_atom_index(atom), &atom_len); + if (IS_NULL_PTR(atom_data)) { + return NULL; + } + char *result = malloc(atom_len + 1); + if (IS_NULL_PTR(result)) { return NULL; } - atom_table_write_cstring(glb->atom_table, atom_ref, len + 1, str); - return str; + memcpy(result, atom_data, atom_len); + result[atom_len] = 0; + return result; } term interop_proplist_get_value(term list, term key) diff --git a/src/libAtomVM/module.c b/src/libAtomVM/module.c index b7bd64e9c..fab674a00 100644 --- a/src/libAtomVM/module.c +++ b/src/libAtomVM/module.c @@ -120,11 +120,11 @@ static enum ModuleLoadResult module_build_imported_functions_table(Module *this_ for (int i = 0; i < functions_count; i++) { int local_module_atom_index = READ_32_UNALIGNED(table_data + i * 12 + 12); int local_function_atom_index = READ_32_UNALIGNED(table_data + i * 12 + 4 + 12); - AtomString module_atom = module_get_atom_string_by_id(this_module, local_module_atom_index, glb); - AtomString function_atom = module_get_atom_string_by_id(this_module, local_function_atom_index, glb); + atom_index_t module_atom = this_module->local_atoms_to_global_table[local_module_atom_index]; + atom_index_t function_atom = this_module->local_atoms_to_global_table[local_function_atom_index]; uint32_t arity = READ_32_UNALIGNED(table_data + i * 12 + 8 + 12); char mfa[MAX_MFA_NAME_LEN]; - atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_atom), atom_string_data(module_atom), atom_string_len(function_atom), atom_string_data(function_atom), arity); + atom_table_write_mfa(glb->atom_table, mfa, sizeof(mfa), module_atom, function_atom, arity); const struct ExportedFunction *bif = bif_registry_get_handler(mfa); @@ -168,7 +168,7 @@ void module_get_imported_function_module_and_name(const Module *this_module, int } #endif -bool module_get_function_from_label(Module *this_module, int label, AtomString *function_name, int *arity, GlobalContext *glb) +bool module_get_function_from_label(Module *this_module, int label, atom_index_t *function_name, int *arity) { int best_label = -1; const uint8_t *export_table_data = (const uint8_t *) this_module->export_table; @@ -180,7 +180,7 @@ bool module_get_function_from_label(Module *this_module, int label, AtomString * if (fun_label <= label && best_label < fun_label) { best_label = fun_label; *arity = fun_arity; - *function_name = module_get_atom_string_by_id(this_module, fun_atom_index, glb); + *function_name = this_module->local_atoms_to_global_table[fun_atom_index]; } } @@ -193,7 +193,7 @@ bool module_get_function_from_label(Module *this_module, int label, AtomString * if (fun_label <= label && best_label < fun_label) { best_label = fun_label; *arity = fun_arity; - *function_name = module_get_atom_string_by_id(this_module, fun_atom_index, glb); + *function_name = this_module->local_atoms_to_global_table[fun_atom_index]; } } if (UNLIKELY(best_label == -1)) { @@ -210,34 +210,38 @@ size_t module_get_exported_functions_count(Module *this_module) return functions_count; } -uint32_t module_search_exported_function(Module *this_module, AtomString func_name, int func_arity, GlobalContext *glb) +uint32_t module_search_exported_function(Module *this_module, atom_index_t func_name, int func_arity) { size_t functions_count = module_get_exported_functions_count(this_module); const uint8_t *table_data = (const uint8_t *) this_module->export_table; for (unsigned int i = 0; i < functions_count; i++) { - AtomString function_atom = module_get_atom_string_by_id(this_module, READ_32_UNALIGNED(table_data + i * 12 + 12), glb); + int local_atom_id = READ_32_UNALIGNED(table_data + i * 12 + 12); int32_t arity = READ_32_UNALIGNED(table_data + i * 12 + 4 + 12); - if ((func_arity == arity) && atom_are_equals(func_name, function_atom)) { - uint32_t label = READ_32_UNALIGNED(table_data + i * 12 + 8 + 12); - return label; + if (func_arity == arity) { + atom_index_t function_atom_ix = this_module->local_atoms_to_global_table[local_atom_id]; + if (func_name == function_atom_ix) { + uint32_t label = READ_32_UNALIGNED(table_data + i * 12 + 8 + 12); + return label; + } } } return 0; } -term module_get_exported_functions(Module *this_module, Heap *heap, GlobalContext *glb) +term module_get_exported_functions(Module *this_module, Heap *heap) { size_t functions_count = module_get_exported_functions_count(this_module); term result_list = term_nil(); const uint8_t *table_data = (const uint8_t *) this_module->export_table; for (unsigned int i = 0; i < functions_count; i++) { - AtomString function_atom = module_get_atom_string_by_id(this_module, READ_32_UNALIGNED(table_data + i * 12 + 12), glb); + int local_atom_id = READ_32_UNALIGNED(table_data + i * 12 + 12); + atom_index_t function_atom_ix = this_module->local_atoms_to_global_table[local_atom_id]; int32_t arity = READ_32_UNALIGNED(table_data + i * 12 + 4 + 12); term function_tuple = term_alloc_tuple(2, heap); - term_put_tuple_element(function_tuple, 0, globalcontext_existing_term_from_atom_string(glb, function_atom)); + term_put_tuple_element(function_tuple, 0, term_from_atom_index(function_atom_ix)); term_put_tuple_element(function_tuple, 1, term_from_int(arity)); result_list = term_list_prepend(function_tuple, result_list, heap); } @@ -464,18 +468,13 @@ term module_load_literal(Module *mod, int index, Context *ctx) const struct ExportedFunction *module_resolve_function0(Module *mod, int import_table_index, struct UnresolvedFunctionCall *unresolved, GlobalContext *glb) { - - AtomString module_name_atom = atom_table_get_atom_string(glb->atom_table, unresolved->module_atom_index); - AtomString function_name_atom = atom_table_get_atom_string(glb->atom_table, unresolved->function_atom_index); - int arity = unresolved->arity; - Module *found_module = globalcontext_get_module(glb, unresolved->module_atom_index); if (LIKELY(found_module != NULL)) { - int exported_label = module_search_exported_function(found_module, function_name_atom, arity, glb); + int exported_label = module_search_exported_function(found_module, unresolved->function_atom_index, unresolved->arity); if (exported_label == 0) { char buf[MAX_MFA_NAME_LEN]; - atom_write_mfa(buf, sizeof(buf), atom_string_len(module_name_atom), atom_string_data(module_name_atom), atom_string_len(function_name_atom), atom_string_data(function_name_atom), arity); + atom_table_write_mfa(glb->atom_table, buf, MAX_MFA_NAME_LEN, unresolved->module_atom_index, unresolved->function_atom_index, unresolved->arity); fprintf(stderr, "Warning: function %s cannot be resolved.\n", buf); return NULL; } @@ -492,9 +491,9 @@ const struct ExportedFunction *module_resolve_function0(Module *mod, int import_ mod->imported_funcs[import_table_index] = &mfunc->base; return &mfunc->base; } else { - char buf[256]; - atom_string_to_c(module_name_atom, buf, 256); - fprintf(stderr, "Warning: module %s cannot be resolved.\n", buf); + size_t atom_string_len; + const uint8_t *atom_string_data = atom_table_get_atom_string(glb->atom_table, unresolved->module_atom_index, &atom_string_len); + fprintf(stderr, "Warning: module %.*s cannot be resolved.\n", (int) atom_string_len, atom_string_data); return NULL; } } diff --git a/src/libAtomVM/module.h b/src/libAtomVM/module.h index 15e380296..b3e099b44 100644 --- a/src/libAtomVM/module.h +++ b/src/libAtomVM/module.h @@ -174,9 +174,8 @@ size_t module_get_exported_functions_count(Module *this_module); * @param this_module the module on which the function will be searched. * @param func_name function name atom string. * @param func_arity function arity. - * @param glb the global context */ -uint32_t module_search_exported_function(Module *this_module, AtomString func_name, int func_arity, GlobalContext *glb); +uint32_t module_search_exported_function(Module *this_module, atom_index_t func_name, int func_arity); /** * @brief Determine heap size of exported functions list. @@ -197,10 +196,9 @@ static inline size_t module_get_exported_functions_list_size(Module *this_module * * @param this_module the module to count exported functions of * @param heap heap to allocate tuples - * @param global global context to fetch atoms * @return a list of exported functions */ -term module_get_exported_functions(Module *this_module, Heap *heap, GlobalContext *global); +term module_get_exported_functions(Module *this_module, Heap *heap); /*** * @brief Destroys an existing Module @@ -230,21 +228,6 @@ Module *module_new_from_iff_binary(GlobalContext *global, const void *iff_binary */ term module_load_literal(Module *mod, int index, Context *ctx); -/** - * @brief Gets the AtomString for the given local atom id - * - * @details Gets an AtomString for the given local atom id from the global table. - * @param mod the module that owns the atom. - * @param local_atom_id module atom table index. - * @param glb the global context. - * @return the AtomString for the given module atom index. - */ -static inline AtomString module_get_atom_string_by_id(const Module *mod, int local_atom_id, GlobalContext *glb) -{ - int global_id = mod->local_atoms_to_global_table[local_atom_id]; - return atom_table_get_atom_string(glb->atom_table, global_id); -} - /** * @brief Gets a term for the given local atom id * @@ -368,9 +351,8 @@ static inline const uint8_t *module_get_str(Module *mod, size_t offset, size_t * * @param label the current label used to look up the function/arity * @param function_name (output) the function name, as an AtomString. * @param arity (output) the function arity - * @param glb the global context */ -bool module_get_function_from_label(Module *this_module, int label, AtomString *function_name, int *arity, GlobalContext *glb); +bool module_get_function_from_label(Module *this_module, int label, atom_index_t *function_name, int *arity); /* * @brief Insert the instruction offset for a given module at a line reference instruction. diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index 70594b9e6..3a7191c7c 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -1445,8 +1445,6 @@ term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) Context *new_ctx = context_new(ctx->global); - AtomString function_string = globalcontext_atomstring_from_term(ctx->global, argv[1]); - Module *found_module = globalcontext_get_module(ctx->global, term_to_atom_index(module_term)); if (UNLIKELY(!found_module)) { return UNDEFINED_ATOM; @@ -1457,7 +1455,7 @@ term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) if (UNLIKELY(!proper)) { RAISE_ERROR(BADARG_ATOM); } - int label = module_search_exported_function(found_module, function_string, args_len, ctx->global); + int label = module_search_exported_function(found_module, term_to_atom_index(argv[1]), args_len); //TODO: fail here if no function has been found if (UNLIKELY(label == 0)) { AVM_ABORT(); @@ -2163,13 +2161,13 @@ static term nif_erlang_atom_to_binary(Context *ctx, int argc, term argv[]) GlobalContext *glb = ctx->global; - int atom_index = term_to_atom_index(atom_term); + atom_index_t atom_index = term_to_atom_index(atom_term); size_t atom_len; - atom_ref_t atom_ref = atom_table_get_atom_ptr_and_len(glb->atom_table, atom_index, &atom_len); + const uint8_t *atom_data = atom_table_get_atom_string(glb->atom_table, atom_index, &atom_len); bool encode_to_latin1 = false; if (encoding == LATIN1_ATOM) { - if (UNLIKELY(!atom_table_is_atom_ref_ascii(glb->atom_table, atom_ref))) { + if (UNLIKELY(!unicode_buf_is_ascii(atom_data, atom_len))) { encode_to_latin1 = true; } } else if (UNLIKELY(encoding != UTF8_ATOM) && (encoding != UNICODE_ATOM)) { @@ -2181,17 +2179,9 @@ static term nif_erlang_atom_to_binary(Context *ctx, int argc, term argv[]) } if (LIKELY(!encode_to_latin1)) { - term binary = term_create_uninitialized_binary(atom_len, &ctx->heap, glb); - atom_table_write_bytes( - glb->atom_table, atom_ref, atom_len, (char *) term_binary_data(binary)); - return binary; + return term_from_const_binary(atom_data, atom_len, &ctx->heap, glb); } else { - uint8_t *utf8_tmp_buf = malloc(atom_len); - if (IS_NULL_PTR(utf8_tmp_buf)) { - RAISE_ERROR(OUT_OF_MEMORY_ATOM); - } - atom_table_write_bytes(glb->atom_table, atom_ref, atom_len, (char *) utf8_tmp_buf); - size_t encoded_len = unicode_buf_utf8_len(utf8_tmp_buf, atom_len); + size_t encoded_len = unicode_buf_utf8_len(atom_data, atom_len); term binary = term_create_uninitialized_binary(encoded_len, &ctx->heap, glb); char *binary_data = (char *) term_binary_data(binary); size_t in_pos = 0; @@ -2199,16 +2189,14 @@ static term nif_erlang_atom_to_binary(Context *ctx, int argc, term argv[]) size_t codepoint_size; uint32_t codepoint; if (UNLIKELY(unicode_utf8_decode( - &utf8_tmp_buf[in_pos], 2, &codepoint, &codepoint_size) + &atom_data[in_pos], 2, &codepoint, &codepoint_size) != UnicodeTransformDecodeSuccess || (codepoint > 255))) { - free(utf8_tmp_buf); RAISE_ERROR(BADARG_ATOM); } binary_data[i] = codepoint; in_pos += codepoint_size; } - free(utf8_tmp_buf); return binary; } } @@ -2263,23 +2251,11 @@ static term nif_erlang_atom_to_list_1(Context *ctx, int argc, term argv[]) term atom_term = argv[0]; VALIDATE_VALUE(atom_term, term_is_atom); - int atom_index = term_to_atom_index(atom_term); + atom_index_t atom_index = term_to_atom_index(atom_term); size_t atom_len; + const uint8_t *atom_data = atom_table_get_atom_string(ctx->global->atom_table, atom_index, &atom_len); - atom_ref_t atom_ref - = atom_table_get_atom_ptr_and_len(ctx->global->atom_table, atom_index, &atom_len); - - // TODO: use stack for smaller atoms - char *atom_buf = malloc(atom_len); - if (IS_NULL_PTR(atom_buf)) { - RAISE_ERROR(OUT_OF_MEMORY_ATOM); - } - - atom_table_write_bytes(ctx->global->atom_table, atom_ref, atom_len, atom_buf); - - term ret = make_list_from_utf8_buf((uint8_t *) atom_buf, atom_len, ctx); - free(atom_buf); - return ret; + return make_list_from_utf8_buf(atom_data, atom_len, ctx); } static size_t lltoa(avm_int64_t int_value, unsigned base, char *integer_string) @@ -3866,14 +3842,12 @@ static term nif_erlang_function_exported(Context *ctx, int argc, term argv[]) VALIDATE_VALUE(arity_term, term_is_integer); atom_index_t module_name_ix = term_to_atom_index(module); - AtomString module_name = atom_table_get_atom_string(ctx->global->atom_table, module_name_ix); atom_index_t function_name_ix = term_to_atom_index(function); - AtomString function_name = atom_table_get_atom_string(ctx->global->atom_table, function_name_ix); avm_int_t arity = term_to_int(arity_term); char mfa[MAX_MFA_NAME_LEN]; - atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_name), atom_string_data(module_name), atom_string_len(function_name), atom_string_data(function_name), arity); + atom_table_write_mfa(ctx->global->atom_table, mfa, sizeof(mfa), module_name_ix, function_name_ix, arity); const struct ExportedFunction *bif = bif_registry_get_handler(mfa); if (bif) { @@ -3890,7 +3864,7 @@ static term nif_erlang_function_exported(Context *ctx, int argc, term argv[]) return FALSE_ATOM; } - int target_label = module_search_exported_function(target_module, function_name, arity, ctx->global); + int target_label = module_search_exported_function(target_module, function_name_ix, arity); if (target_label == 0) { return FALSE_ATOM; } @@ -4026,20 +4000,20 @@ static term nif_erlang_fun_info_2(Context *ctx, int argc, term argv[]) switch (key) { case MODULE_ATOM: { term module_name; - term_get_function_mfa(fun, &module_name, NULL, NULL, ctx->global); + term_get_function_mfa(fun, &module_name, NULL, NULL); value = module_name; break; } case NAME_ATOM: { term function_name; - term_get_function_mfa(fun, NULL, &function_name, NULL, ctx->global); + term_get_function_mfa(fun, NULL, &function_name, NULL); value = function_name; break; } case ARITY_ATOM: { term arity; - term_get_function_mfa(fun, NULL, NULL, &arity, ctx->global); + term_get_function_mfa(fun, NULL, NULL, &arity); value = arity; break; } @@ -4433,7 +4407,7 @@ static term nif_erlang_get_module_info(Context *ctx, int argc, term argv[]) if (UNLIKELY(memory_ensure_free(ctx, info_size) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } - term exports = module_get_exported_functions(target_module, &ctx->heap, ctx->global); + term exports = module_get_exported_functions(target_module, &ctx->heap); if (argc == 2) { return exports; } @@ -4775,30 +4749,22 @@ static term nif_atomvm_read_priv(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - int atom_index = term_to_atom_index(app_term); + atom_index_t atom_index = term_to_atom_index(app_term); size_t app_len; - atom_ref_t atom_ref = atom_table_get_atom_ptr_and_len(glb->atom_table, atom_index, &app_len); - char *app = malloc(app_len + 1); - if (IS_NULL_PTR(app)) { - RAISE_ERROR(OUT_OF_MEMORY_ATOM); - } - atom_table_write_cstring(glb->atom_table, atom_ref, app_len + 1, app); + const uint8_t *app_data = atom_table_get_atom_string(glb->atom_table, atom_index, &app_len); int ok; char *path = interop_term_to_string(path_term, &ok); if (UNLIKELY(!ok)) { - free(app); RAISE_ERROR(BADARG_ATOM); } if (UNLIKELY(!path)) { - free(app); RAISE_ERROR(OUT_OF_MEMORY_ATOM); } int complete_path_len = app_len + strlen("/priv/") + strlen(path) + 1; char *complete_path = malloc(complete_path_len); - snprintf(complete_path, complete_path_len, "%s/priv/%s", app, path); - free(app); + snprintf(complete_path, complete_path_len, "%.*s/priv/%s", (int) app_len, app_data, path); free(path); const void *bin_data; @@ -5232,14 +5198,12 @@ static void *nif_code_all_available_fold(void *accum, const void *section_ptr, u bool loaded; if (acc->avmpack_data->in_use) { // Check if module is loaded - char atom_str[module_name_len + 1]; - atom_str[0] = module_name_len; - memcpy(atom_str + 1, section_name, module_name_len); - term module_name_atom = globalcontext_insert_atom_maybe_copy(acc->ctx->global, (AtomString) atom_str, true); - if (UNLIKELY(term_is_invalid_term(module_name_atom))) { + atom_index_t module_name_ix; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(acc->ctx->global->atom_table, (const uint8_t *) section_name, module_name_len, AtomTableAlreadyExisting, &module_name_ix); + if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { loaded = false; } else { - Module *loaded_module = globalcontext_get_module(acc->ctx->global, term_to_atom_index(module_name_atom)); + Module *loaded_module = globalcontext_get_module(acc->ctx->global, module_name_ix); loaded = loaded_module != NULL; } } else { @@ -5299,8 +5263,12 @@ static term nif_code_all_available(Context *ctx, int argc, term argv[]) for (size_t ix = 0; ix < available_count - acc.acc_count; ix++) { Module *module = globalcontext_get_module_by_index(ctx->global, ix); term module_tuple = term_alloc_tuple(3, &ctx->heap); - AtomString module_atom_str = globalcontext_atomstring_from_term(ctx->global, module_get_name(module)); - term_put_tuple_element(module_tuple, 0, term_from_const_binary(((const char *) module_atom_str) + 1, ((const char *) module_atom_str)[0], &ctx->heap, ctx->global)); + term module_atom = module_get_name(module); + atom_index_t module_atom_ix = term_to_atom_index(module_atom); + size_t module_atom_len; + const uint8_t *data = atom_table_get_atom_string(ctx->global->atom_table, module_atom_ix, &module_atom_len); + term module_name_binary = term_from_const_binary(data, module_atom_len, &ctx->heap, ctx->global); + term_put_tuple_element(module_tuple, 0, module_name_binary); term_put_tuple_element(module_tuple, 1, UNDEFINED_ATOM); term_put_tuple_element(module_tuple, 2, TRUE_ATOM); acc.result = term_list_prepend(module_tuple, acc.result, &ctx->heap); @@ -5443,8 +5411,8 @@ static term nif_erlang_module_loaded(Context *ctx, int argc, term argv[]) term module_atom = argv[0]; VALIDATE_VALUE(module_atom, term_is_atom); - AtomString module_string = globalcontext_atomstring_from_term(ctx->global, module_atom); - Module *module = (Module *) atomshashtable_get_value(ctx->global->modules_table, module_string, (unsigned long) NULL); + atom_index_t module_name_ix = term_to_atom_index(module_atom); + Module *module = globalcontext_get_module(ctx->global, module_name_ix); return module != NULL ? TRUE_ATOM : FALSE_ATOM; } diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index eb82e4dcf..59c136803 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -1229,8 +1229,8 @@ static void destroy_extended_registers(Context *ctx, unsigned int live) if (term_is_atom(index_or_function)) { \ term module = boxed_value[1]; \ fun_arity = term_to_int(boxed_value[3]); \ - AtomString module_name = globalcontext_atomstring_from_term(glb, module); \ - AtomString function_name = globalcontext_atomstring_from_term(glb, index_or_function); \ + atom_index_t module_name = term_to_atom_index(module); \ + atom_index_t function_name = term_to_atom_index(index_or_function); \ term return_value; \ if (maybe_call_native(ctx, module_name, function_name, fun_arity, &return_value)) { \ PROCESS_MAYBE_TRAP_RETURN_VALUE(return_value); \ @@ -1247,7 +1247,7 @@ static void destroy_extended_registers(Context *ctx, unsigned int live) SET_ERROR(UNDEF_ATOM); \ HANDLE_ERROR(); \ } \ - label = module_search_exported_function(fun_module, function_name, fun_arity, glb); \ + label = module_search_exported_function(fun_module, function_name, fun_arity); \ if (UNLIKELY(label == 0)) { \ SET_ERROR(UNDEF_ATOM); \ HANDLE_ERROR(); \ @@ -1695,11 +1695,11 @@ term make_fun(Context *ctx, const Module *mod, int fun_index, term argv[]) return ((term) boxed_func) | TERM_BOXED_VALUE_TAG; } -static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString function_name, int arity, +static bool maybe_call_native(Context *ctx, atom_index_t module_name, atom_index_t function_name, int arity, term *return_value) { char mfa[MAX_MFA_NAME_LEN]; - atom_write_mfa(mfa, sizeof(mfa), atom_string_len(module_name), atom_string_data(module_name), atom_string_len(function_name), atom_string_data(function_name), arity); + atom_table_write_mfa(ctx->global->atom_table, mfa, sizeof(mfa), module_name, function_name, arity); const struct ExportedFunction *exported_bif = bif_registry_get_handler(mfa); if (exported_bif) { if (exported_bif->type == GCBIFFunctionType) { @@ -1872,14 +1872,14 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f #ifdef IMPL_EXECUTE_LOOP TRACE("-- Executing code\n"); - int function_len = strlen(function_name); - uint8_t *tmp_atom_name = malloc(function_len + 1); - tmp_atom_name[0] = function_len; - memcpy(tmp_atom_name + 1, function_name, function_len); - - int label = module_search_exported_function(mod, tmp_atom_name, arity, ctx->global); - free(tmp_atom_name); + atom_index_t function_name_index; + enum AtomTableEnsureAtomResult ensure_result = atom_table_ensure_atom(ctx->global->atom_table, (const uint8_t *) function_name, strlen(function_name), AtomTableAlreadyExisting, &function_name_index); + if (UNLIKELY(ensure_result != AtomTableEnsureAtomOk)) { + fprintf(stderr, "No %s/%i function found.\n", function_name, arity); + return 0; + } + int label = module_search_exported_function(mod, function_name_index, arity); if (UNLIKELY(!label)) { fprintf(stderr, "No %s/%i function found.\n", function_name, arity); return 0; @@ -5405,8 +5405,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) RAISE_ERROR(BADARG_ATOM); } - AtomString module_name = globalcontext_atomstring_from_term(glb, module); - AtomString function_name = globalcontext_atomstring_from_term(glb, function); + atom_index_t module_name = term_to_atom_index(module); + atom_index_t function_name = term_to_atom_index(function); TRACE_APPLY(ctx, "apply", module_name, function_name, arity); @@ -5422,7 +5422,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) SET_ERROR(UNDEF_ATOM); HANDLE_ERROR(); } - int target_label = module_search_exported_function(target_module, function_name, arity, glb); + int target_label = module_search_exported_function(target_module, function_name, arity); if (target_label == 0) { pc = orig_pc; SET_ERROR(UNDEF_ATOM); @@ -5463,8 +5463,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) RAISE_ERROR(BADARG_ATOM); } - AtomString module_name = globalcontext_atomstring_from_term(glb, module); - AtomString function_name = globalcontext_atomstring_from_term(glb, function); + atom_index_t module_name = term_to_atom_index(module); + atom_index_t function_name = term_to_atom_index(function); TRACE_APPLY(ctx, "apply_last", module_name, function_name, arity); @@ -5480,7 +5480,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) SET_ERROR(UNDEF_ATOM); HANDLE_ERROR(); } - int target_label = module_search_exported_function(target_module, function_name, arity, glb); + int target_label = module_search_exported_function(target_module, function_name, arity); if (target_label == 0) { SET_ERROR(UNDEF_ATOM); HANDLE_ERROR(); diff --git a/src/libAtomVM/stacktrace.c b/src/libAtomVM/stacktrace.c index 6263f1ecc..f4ac58622 100644 --- a/src/libAtomVM/stacktrace.c +++ b/src/libAtomVM/stacktrace.c @@ -83,8 +83,10 @@ static bool location_sets_append(GlobalContext *global, Module *mod, const uint8 const void *key = filename; if (IS_NULL_PTR(filename)) { key = mod; - AtomString module_name_atom_str = globalcontext_atomstring_from_term(global, module_get_name(mod)); - filename_len = atom_string_len(module_name_atom_str) + 4; // ".erl" + size_t module_name_len; + const uint8_t *module_name_data = atom_table_get_atom_string(global->atom_table, term_to_atom_index(module_get_name(mod)), &module_name_len); + UNUSED(module_name_data); + filename_len = module_name_len + 4; // ".erl" } for (size_t i = 0; i < locations_set_size; i++) { if (locations_set[i] == key) { @@ -358,15 +360,16 @@ term stacktrace_build(Context *ctx, term *stack_info, uint32_t live) term path = find_path_created(key, module_paths, module_path_idx); if (term_is_invalid_term(path)) { if (IS_NULL_PTR(filename)) { - AtomString module_name_atom_str = globalcontext_atomstring_from_term(ctx->global, module_get_name(cp_mod)); - uint8_t *default_filename = malloc(atom_string_len(module_name_atom_str) + 4); + size_t module_name_len; + const uint8_t *module_name_data = atom_table_get_atom_string(ctx->global->atom_table, term_to_atom_index(module_get_name(cp_mod)), &module_name_len); + uint8_t *default_filename = malloc(module_name_len + 4); if (IS_NULL_PTR(default_filename)) { free(module_paths); return OUT_OF_MEMORY_ATOM; } - memcpy(default_filename, atom_string_data(module_name_atom_str), atom_string_len(module_name_atom_str)); - memcpy(default_filename + atom_string_len(module_name_atom_str), ".erl", 4); - path = term_from_string(default_filename, atom_string_len(module_name_atom_str) + 4, &ctx->heap); + memcpy(default_filename, module_name_data, module_name_len); + memcpy(default_filename + module_name_len, ".erl", 4); + path = term_from_string(default_filename, module_name_len + 4, &ctx->heap); free(default_filename); } else { path = term_from_string(filename, filename_len, &ctx->heap); @@ -381,12 +384,12 @@ term stacktrace_build(Context *ctx, term *stack_info, uint32_t live) } term_put_tuple_element(frame_i, 3, aux_data); - AtomString function_name = NULL; + atom_index_t function_name; int arity = 0; - bool result = module_get_function_from_label(cp_mod, label, &function_name, &arity, glb); + bool result = module_get_function_from_label(cp_mod, label, &function_name, &arity); if (LIKELY(result)) { - term_put_tuple_element(frame_i, 1, globalcontext_make_atom(glb, function_name)); + term_put_tuple_element(frame_i, 1, term_from_atom_index(function_name)); term_put_tuple_element(frame_i, 2, term_from_int(arity)); } else { term_put_tuple_element(frame_i, 1, UNDEFINED_ATOM); diff --git a/src/libAtomVM/term.c b/src/libAtomVM/term.c index 81f845d26..668bb801d 100644 --- a/src/libAtomVM/term.c +++ b/src/libAtomVM/term.c @@ -115,10 +115,10 @@ int term_snprint(char *buf, size_t size, term t, const GlobalContext *global) int term_funprint(PrinterFun *fun, term t, const GlobalContext *global) { if (term_is_atom(t)) { - int atom_index = term_to_atom_index(t); - AtomString atom_string = atom_table_get_atom_string(global->atom_table, atom_index); - return fun->print(fun, "%.*s", (int) atom_string_len(atom_string), - (char *) atom_string_data(atom_string)); + atom_index_t atom_index = term_to_atom_index(t); + size_t atom_len; + const uint8_t *atom_data = atom_table_get_atom_string(global->atom_table, atom_index, &atom_len); + return fun->print(fun, "%.*s", (int) atom_len, atom_data); } else if (term_is_integer(t)) { avm_int_t iv = term_to_int(t); @@ -222,57 +222,33 @@ int term_funprint(PrinterFun *fun, term t, const GlobalContext *global) term function_atom = boxed_value[2]; int arity = term_to_int(boxed_value[3]); - int module_atom_index = term_to_atom_index(module_atom); - size_t module_buf_len; - atom_ref_t module_atom_ref = atom_table_get_atom_ptr_and_len( - global->atom_table, module_atom_index, &module_buf_len); - char *module_name = malloc(module_buf_len); - if (IS_NULL_PTR(module_name)) { - return -1; - } - atom_table_write_bytes( - global->atom_table, module_atom_ref, module_buf_len, module_name); - - int function_atom_index = term_to_atom_index(function_atom); - size_t function_buf_len; - atom_ref_t function_atom_ref = atom_table_get_atom_ptr_and_len( - global->atom_table, function_atom_index, &function_buf_len); - char *function_name = malloc(function_buf_len); - if (IS_NULL_PTR(function_name)) { - free(module_name); - return -1; - } - atom_table_write_bytes( - global->atom_table, function_atom_ref, function_buf_len, function_name); + atom_index_t module_atom_index = term_to_atom_index(module_atom); + size_t module_name_len; + const uint8_t *module_name = atom_table_get_atom_string(global->atom_table, module_atom_index, &module_name_len); + + atom_index_t function_atom_index = term_to_atom_index(function_atom); + size_t function_name_len; + const uint8_t *function_name = atom_table_get_atom_string(global->atom_table, function_atom_index, &function_name_len); // fun m:f/a - int ret = fun->print(fun, "fun %.*s:%.*s/%i", (int) module_buf_len, module_name, - (int) function_buf_len, function_name, arity); - free(module_name); - free(function_name); + int ret = fun->print(fun, "fun %.*s:%.*s/%i", (int) module_name_len, module_name, + (int) function_name_len, function_name, arity); return ret; } else { Module *fun_module = (Module *) boxed_value[1]; term module_name_atom = module_get_name(fun_module); - int atom_index = term_to_atom_index(module_name_atom); - size_t buf_len; - atom_ref_t atom_ref - = atom_table_get_atom_ptr_and_len(global->atom_table, atom_index, &buf_len); - char *module_name = malloc(buf_len); - if (IS_NULL_PTR(module_name)) { - return -1; - } - atom_table_write_bytes(global->atom_table, atom_ref, buf_len, module_name); + atom_index_t module_atom_index = term_to_atom_index(module_name_atom); + size_t module_name_len; + const uint8_t *module_name = atom_table_get_atom_string(global->atom_table, module_atom_index, &module_name_len); // this is not the same fun_index used on the BEAM, but it should be fine uint32_t fun_index = boxed_value[2]; // TODO: last component is a uniq, we are temporarly using the memory address - int ret = fun->print(fun, "#Fun<%.*s.%" PRIu32 ".%" PRIuPTR ">", (int) buf_len, + int ret = fun->print(fun, "#Fun<%.*s.%" PRIu32 ".%" PRIuPTR ">", (int) module_name_len, module_name, fun_index, (uintptr_t) fun_module); - free(module_name); return ret; } @@ -819,7 +795,7 @@ TermCompareResult term_compare(term t, term other, TermCompareOpts opts, GlobalC return result; } -void term_get_function_mfa(term fun, term *m, term *f, term *a, GlobalContext *global) +void term_get_function_mfa(term fun, term *m, term *f, term *a) { TERM_DEBUG_ASSERT(term_is_fun(fun)); @@ -847,10 +823,10 @@ void term_get_function_mfa(term fun, term *m, term *f, term *a, GlobalContext *g uint32_t label, arity, n_freeze; module_get_fun(module, fun_index, &label, &arity, &n_freeze); - AtomString fun_name = NULL; - bool has_local_name = module_get_function_from_label(module, label, &fun_name, (int *) &arity, global); + atom_index_t fun_name; + bool has_local_name = module_get_function_from_label(module, label, &fun_name, (int *) &arity); - *f = has_local_name ? globalcontext_make_atom(global, fun_name) : term_nil(); + *f = has_local_name ? term_from_atom_index(fun_name) : term_nil(); } if (a != NULL) { uint32_t fun_index = term_to_int32(boxed_value[2]); diff --git a/src/libAtomVM/term.h b/src/libAtomVM/term.h index 14b927976..6b766d2df 100644 --- a/src/libAtomVM/term.h +++ b/src/libAtomVM/term.h @@ -1972,10 +1972,9 @@ static inline bool term_is_string(term t) * @param m module name as an atom. * @param f function name as an atom. * @param a function arity as an integer. - * @param global the \c GlobalContext used for creating function name atoms. * */ -void term_get_function_mfa(term fun, term *m, term *f, term *a, GlobalContext *global); +void term_get_function_mfa(term fun, term *m, term *f, term *a); static inline term term_make_function_reference(term m, term f, term a, Heap *heap) { diff --git a/src/platforms/emscripten/src/main.c b/src/platforms/emscripten/src/main.c index f2bedb446..3ecd15b00 100644 --- a/src/platforms/emscripten/src/main.c +++ b/src/platforms/emscripten/src/main.c @@ -74,7 +74,7 @@ static int load_module(const char *path) } else if (ext && strcmp(ext, ".beam") == 0) { Module *module = sys_load_module_from_file(global, path); globalcontext_insert_module(global, module); - if (IS_NULL_PTR(main_module) && module_search_exported_function(module, ATOM_STR("\5", "start"), 0, global) != 0) { + if (IS_NULL_PTR(main_module) && module_search_exported_function(module, START_ATOM_INDEX, 0) != 0) { main_module = module; } } else { diff --git a/src/platforms/esp32/components/avm_builtins/nvs_nif.c b/src/platforms/esp32/components/avm_builtins/nvs_nif.c index acb136f83..c41cab688 100644 --- a/src/platforms/esp32/components/avm_builtins/nvs_nif.c +++ b/src/platforms/esp32/components/avm_builtins/nvs_nif.c @@ -319,11 +319,14 @@ const struct Nif *nvs_nif_get_nif(const char *nifname) static int write_atom_c_string(Context *ctx, char *buf, size_t bufsize, term t) { - AtomString atom_string = globalcontext_atomstring_from_term(ctx->global, t); - if (atom_string == NULL) { + size_t t_atom_len; + const uint8_t *t_atom_data = atom_table_get_atom_string(ctx->global->atom_table, term_to_atom_index(t), &t_atom_len); + if (IS_NULL_PTR(t_atom_data)) { return -1; } - atom_string_to_c(atom_string, buf, bufsize); + + memcpy(buf, t_atom_data, t_atom_len); + buf[t_atom_len] = 0; return 0; } diff --git a/src/platforms/generic_unix/main.c b/src/platforms/generic_unix/main.c index a5b5fbacb..f2c96f53f 100644 --- a/src/platforms/generic_unix/main.c +++ b/src/platforms/generic_unix/main.c @@ -131,7 +131,7 @@ int main(int argc, char **argv) } globalcontext_insert_module(glb, mod); mod->module_platform_data = NULL; - if (IS_NULL_PTR(startup_module) && module_search_exported_function(mod, ATOM_STR("\5", "start"), 0, glb) != 0) { + if (IS_NULL_PTR(startup_module) && module_search_exported_function(mod, START_ATOM_INDEX, 0) != 0) { startup_module = mod; } diff --git a/tests/erlang_tests/test_binary_to_atom.erl b/tests/erlang_tests/test_binary_to_atom.erl index 78498e96b..bec0b3b62 100644 --- a/tests/erlang_tests/test_binary_to_atom.erl +++ b/tests/erlang_tests/test_binary_to_atom.erl @@ -23,6 +23,7 @@ -export([start/0, f/1, g/1, h/1, i/1]). start() -> + ok = test_more_than_255_bytes(), f(i(h(g(2)))) + f(i(h(g(10)))) + f(i(h(g(20)))). f(not_an_atom) -> @@ -56,3 +57,30 @@ i(A) -> catch _:_ -> not_an_atom end. + +test_more_than_255_bytes() -> + Suffix = duplicate(<<"-">>, 252, <<>>), + Str = <<"γ‚’γƒˆγƒ "/utf8, Suffix/binary>>, + 261 = byte_size(Str), + _LongAtom = binary_to_atom(id(Str), utf8), + % biggest atom is 1020 bytes + MoonStr = <<"πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜"/utf8>>, + 32 = byte_size(MoonStr), + Moons256Str = duplicate(MoonStr, 32, <<>>), + 1024 = byte_size(Moons256Str), + <<"πŸŒ‘"/utf8, Moons255Str/binary>> = Moons256Str, + 1020 = byte_size(Moons255Str), + _LongestAtom = binary_to_atom(id(Moons255Str), utf8), + ok = + try + _ = binary_to_atom(id(<>), utf8), + should_have_raised + catch + error:system_limit -> ok + end. + +id(X) -> + X. + +duplicate(_Binary, 0, Acc) -> Acc; +duplicate(Binary, N, Acc) -> duplicate(Binary, N - 1, <>). diff --git a/tests/erlang_tests/test_binary_to_term.erl b/tests/erlang_tests/test_binary_to_term.erl index ffc97c2cb..f71cc5c2b 100644 --- a/tests/erlang_tests/test_binary_to_term.erl +++ b/tests/erlang_tests/test_binary_to_term.erl @@ -177,6 +177,7 @@ start() -> ok = test_encode_pid(), ok = test_encode_reference(), ok = test_encode_port(), + ok = test_atom_encoding(), 0. test_reverse(T, Interop) -> @@ -339,6 +340,13 @@ get_binary(Id) -> % 'hello' latin1_as_utf8_3 -> <<131, 119, 5, 104, 101, 108, 108, 111>>; + % 'hello' + short_with_two_bytes_length -> + <<131, 118, 5:16, "hello">>; + % 'hello' + long_with_two_bytes_length -> + <<131, 118, 256:16, + "πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜"/utf8>>; % valid length, but truncated utf8 invalid_utf8_1 -> <<131, 119, 5, 230, 188, 162, 229, 173>>; @@ -364,14 +372,29 @@ get_binary(Id) -> get_atom(Id) -> case Id of - latin1_1 -> 'buondΓ¬'; - latin1_2 -> 'ðñ÷aΓΎbΓΏ'; - latin1_3 -> 'hello'; - jp_1 -> 'ζΌ’ε­—'; - jp_2 -> 'Unicodeγ§δ½Ώγˆγ‚‹8γƒ“γƒƒγƒˆ'; - latin1_as_utf8_1 -> 'buondΓ¬'; - latin1_as_utf8_2 -> 'ðñ÷aΓΎbΓΏ'; - latin1_as_utf8_3 -> 'hello' + latin1_1 -> + 'buondΓ¬'; + latin1_2 -> + 'ðñ÷aΓΎbΓΏ'; + latin1_3 -> + 'hello'; + jp_1 -> + 'ζΌ’ε­—'; + jp_2 -> + 'Unicodeγ§δ½Ώγˆγ‚‹8γƒ“γƒƒγƒˆ'; + latin1_as_utf8_1 -> + 'buondΓ¬'; + latin1_as_utf8_2 -> + 'ðñ÷aΓΎbΓΏ'; + latin1_as_utf8_3 -> + 'hello'; + short_with_two_bytes_length -> + 'hello'; + % literal only works with OTP >= 28 + long_with_two_bytes_length -> + list_to_atom( + ?MODULE:id("πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜") + ) end. test_atom_decoding() -> @@ -383,6 +406,8 @@ test_atom_decoding() -> true = compare_pair(latin1_as_utf8_1), true = compare_pair(latin1_as_utf8_2), true = compare_pair(latin1_as_utf8_3), + true = compare_pair(short_with_two_bytes_length), + true = compare_pair(long_with_two_bytes_length), ok. test_atom_decoding_checks() -> @@ -1008,6 +1033,13 @@ binary_to_term_idempotent(Binary, OTPVersion) -> end, Term. +test_atom_encoding() -> + true = compare_pair_encoding(latin1_as_utf8_1), + true = compare_pair_encoding(latin1_as_utf8_2), + true = compare_pair_encoding(latin1_as_utf8_3), + true = compare_pair_encoding(long_with_two_bytes_length), + ok. + make_binterm_fun(Id) -> fun() -> Bin = ?MODULE:get_binary(Id), @@ -1019,6 +1051,18 @@ compare_pair(Id) -> B = ?MODULE:get_binary(Id), A == erlang:binary_to_term(B). +compare_pair_encoding(Id) -> + A = ?MODULE:get_atom(Id), + B = ?MODULE:get_binary(Id), + A = erlang:binary_to_term(erlang:term_to_binary(A)), + OTPVersion = get_otp_version(), + if + OTPVersion =:= atomvm orelse OTPVersion >= 26 -> + B == erlang:term_to_binary(A); + true -> + true + end. + % We don't have access to erlang module in tests. apply(F, []) -> F(); diff --git a/tests/erlang_tests/test_list_to_atom.erl b/tests/erlang_tests/test_list_to_atom.erl index 5c80cfcc1..60ce94aff 100644 --- a/tests/erlang_tests/test_list_to_atom.erl +++ b/tests/erlang_tests/test_list_to_atom.erl @@ -20,9 +20,10 @@ -module(test_list_to_atom). --export([start/0, f/1, g/1, h/1, i/1]). +-export([start/0, f/1, g/1, h/1, i/1, id/1]). start() -> + ok = test_more_than_255_bytes(), f(i(h(g(2)))) + f(i(h(g(10)))) + i(10). f(hello) -> @@ -55,3 +56,30 @@ i(A) -> error:badarg -> 0; _:_ -> -1024 end. + +test_more_than_255_bytes() -> + Suffix = duplicate("-", 252, ""), + Str = "γ‚’γƒˆγƒ " ++ Suffix, + 255 = length(Str), + _ = list_to_atom(id(Str)), + % biggest atom is 1020 bytes + MoonStr = "πŸŒ‘πŸŒ’πŸŒ“πŸŒ”πŸŒ•πŸŒ–πŸŒ—πŸŒ˜", + 8 = length(MoonStr), + Moons256Str = duplicate(MoonStr, 32, ""), + 256 = length(Moons256Str), + "πŸŒ‘" ++ Moons255Str = Moons256Str, + _ = list_to_atom(id(Moons255Str)), + + ok = + try + _ = list_to_atom(id(Str ++ "o")), + should_have_raised + catch + error:system_limit -> ok + end. + +id(X) -> + X. + +duplicate(_List, 0, Acc) -> Acc; +duplicate(List, N, Acc) -> duplicate(List, N - 1, List ++ Acc). diff --git a/tests/test-structs.c b/tests/test-structs.c index 3fed8fd72..c244e8028 100644 --- a/tests/test-structs.c +++ b/tests/test-structs.c @@ -186,248 +186,248 @@ atom_index_t insert_atoms_into_atom_table(struct AtomTable *table) atom_index_t decimals_index; enum AtomTableEnsureAtomResult r; - r = atom_table_ensure_atom(table, false_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) false_atom + 1, false_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, true_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) true_atom + 1, true_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, ok_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) ok_atom + 1, ok_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, error_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) error_atom + 1, error_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, undefined_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) undefined_atom + 1, undefined_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badarg_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badarg_atom + 1, badarg_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badarith_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badarith_atom + 1, badarith_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badarity_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badarity_atom + 1, badarity_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badfun_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badfun_atom + 1, badfun_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, function_clause_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) function_clause_atom + 1, function_clause_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, try_clause_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) try_clause_atom + 1, try_clause_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, out_of_memory_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) out_of_memory_atom + 1, out_of_memory_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, overflow_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) overflow_atom + 1, overflow_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, system_limit_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) system_limit_atom + 1, system_limit_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, flush_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) flush_atom + 1, flush_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, heap_size_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) heap_size_atom + 1, heap_size_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, latin1_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) latin1_atom + 1, latin1_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, max_heap_size_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) max_heap_size_atom + 1, max_heap_size_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, memory_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) memory_atom + 1, memory_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, message_queue_len_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) message_queue_len_atom + 1, message_queue_len_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, puts_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) puts_atom + 1, puts_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, stack_size_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) stack_size_atom + 1, stack_size_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, min_heap_size_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) min_heap_size_atom + 1, min_heap_size_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, process_count_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) process_count_atom + 1, process_count_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, port_count_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) port_count_atom + 1, port_count_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, atom_count_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) atom_count_atom + 1, atom_count_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, system_architecture_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) system_architecture_atom + 1, system_architecture_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, wordsize_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) wordsize_atom + 1, wordsize_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, decimals_atom, AtomTableNoOpts, &decimals_index); + r = atom_table_ensure_atom(table, (const uint8_t *) decimals_atom + 1, decimals_atom[0], AtomTableNoOpts, &decimals_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, scientific_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) scientific_atom + 1, scientific_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, compact_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) compact_atom + 1, compact_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badmatch_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badmatch_atom + 1, badmatch_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, case_clause_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) case_clause_atom + 1, case_clause_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, if_clause_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) if_clause_atom + 1, if_clause_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, throw_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) throw_atom + 1, throw_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, low_entropy_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) low_entropy_atom + 1, low_entropy_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, unsupported_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) unsupported_atom + 1, unsupported_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, used_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) used_atom + 1, used_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, all_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) all_atom + 1, all_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, start_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) start_atom + 1, start_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, undef_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) undef_atom + 1, undef_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, vm_abort_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) vm_abort_atom + 1, vm_abort_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, link_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) link_atom + 1, link_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, monitor_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) monitor_atom + 1, monitor_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, normal_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) normal_atom + 1, normal_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, down_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) down_atom + 1, down_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, process_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) process_atom + 1, process_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, nocatch_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) nocatch_atom + 1, nocatch_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, refc_binary_info_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) refc_binary_info_atom + 1, refc_binary_info_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, noproc_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) noproc_atom + 1, noproc_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, trap_exit_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) trap_exit_atom + 1, trap_exit_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, exit_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) exit_atom + 1, exit_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badmap_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badmap_atom + 1, badmap_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badkey_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badkey_atom + 1, badkey_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, none_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) none_atom + 1, none_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, io_request_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) io_request_atom + 1, io_request_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, io_reply_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) io_reply_atom + 1, io_reply_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, put_chars_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) put_chars_atom + 1, put_chars_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, lowercase_exit_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) lowercase_exit_atom + 1, lowercase_exit_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, atomvm_version_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) atomvm_version_atom + 1, atomvm_version_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, second_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) second_atom + 1, second_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, millisecond_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) millisecond_atom + 1, millisecond_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, microsecond_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) microsecond_atom + 1, microsecond_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, infinity_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) infinity_atom + 1, infinity_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, timeout_value_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) timeout_value_atom + 1, timeout_value_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, schedulers_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) schedulers_atom + 1, schedulers_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, schedulers_online_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) schedulers_online_atom + 1, schedulers_online_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, append_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) append_atom + 1, append_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, private_append_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) private_append_atom + 1, private_append_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, binary_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) binary_atom + 1, binary_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, integer_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) integer_atom + 1, integer_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, little_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) little_atom + 1, little_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, native_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) native_atom + 1, native_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, string_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) string_atom + 1, string_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, utf8_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) utf8_atom + 1, utf8_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, utf16_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) utf16_atom + 1, utf16_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, utf32_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) utf32_atom + 1, utf32_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, badrecord_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) badrecord_atom + 1, badrecord_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, copy_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) copy_atom + 1, copy_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, reuse_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) reuse_atom + 1, reuse_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, ensure_at_least_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) ensure_at_least_atom + 1, ensure_at_least_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, ensure_exactly_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) ensure_exactly_atom + 1, ensure_exactly_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, skip_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) skip_atom + 1, skip_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, get_tail_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) get_tail_atom + 1, get_tail_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, equal_colon_equal_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) equal_colon_equal_atom + 1, equal_colon_equal_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, signed_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) signed_atom + 1, signed_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, machine_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) machine_atom + 1, machine_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, avm_floatsize_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) avm_floatsize_atom + 1, avm_floatsize_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, close_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) close_atom + 1, close_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, closed_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) closed_atom + 1, closed_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, port_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) port_atom + 1, port_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, info_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) info_atom + 1, info_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, module_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) module_atom + 1, module_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, select_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) select_atom + 1, select_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, ready_input_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) ready_input_atom + 1, ready_input_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, ready_output_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) ready_output_atom + 1, ready_output_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, attributes_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) attributes_atom + 1, attributes_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, compile_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) compile_atom + 1, compile_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, exports_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) exports_atom + 1, exports_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, incomplete_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) incomplete_atom + 1, incomplete_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, kill_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) kill_atom + 1, kill_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, killed_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) killed_atom + 1, killed_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, links_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) links_atom + 1, links_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, total_heap_size_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) total_heap_size_atom + 1, total_heap_size_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, atomvm_heap_growth_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) atomvm_heap_growth_atom + 1, atomvm_heap_growth_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, bounded_free_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) bounded_free_atom + 1, bounded_free_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, minimum_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) minimum_atom + 1, minimum_atom[0], AtomTableNoOpts, &global_atom_index); assert(r == AtomTableEnsureAtomOk); - r = atom_table_ensure_atom(table, fibonacci_atom, AtomTableNoOpts, &global_atom_index); + r = atom_table_ensure_atom(table, (const uint8_t *) fibonacci_atom + 1, fibonacci_atom[0], AtomTableNoOpts, &global_atom_index); return decimals_index; } @@ -438,36 +438,39 @@ void test_atom_table() enum AtomTableEnsureAtomResult r; atom_index_t new_index; - r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableAlreadyExisting, &new_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "ciao", 4, AtomTableAlreadyExisting, &new_index); assert(r == AtomTableEnsureAtomNotFound); - r = atom_table_ensure_atom(table, "\x3" "bar", AtomTableNoOpts, &new_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "bar", 3, AtomTableNoOpts, &new_index); assert(r == AtomTableEnsureAtomOk); assert(new_index == 0); atom_index_t ciao_index; - r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableNoOpts, &ciao_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "ciao", 4, AtomTableNoOpts, &ciao_index); assert(r == AtomTableEnsureAtomOk); assert(ciao_index == 1); atom_index_t foo_index; - r = atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts, &foo_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "foo", 3, AtomTableNoOpts, &foo_index); assert(r == AtomTableEnsureAtomOk); assert(foo_index == 2); - r = atom_table_ensure_atom(table, "\x3" "foo", AtomTableNoOpts, &foo_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "foo", 3, AtomTableNoOpts, &foo_index); assert(r == AtomTableEnsureAtomOk); assert(foo_index == 2); - r = atom_table_ensure_atom(table, "\x4" "ciao", AtomTableAlreadyExisting, &ciao_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "ciao", 4, AtomTableAlreadyExisting, &ciao_index); assert(r == AtomTableEnsureAtomOk); assert(ciao_index == 1); - assert(((char *) atom_table_get_atom_string(table, 0))[0] == 3); + size_t atom_len_0; + const uint8_t *atom_data_0 = atom_table_get_atom_string(table, 0, &atom_len_0); + UNUSED(atom_data_0); + assert(atom_len_0 == 3); atom_index_t decimals_index = insert_atoms_into_atom_table(table); - r = atom_table_ensure_atom(table, "\x8" "decimals", AtomTableNoOpts, &new_index); + r = atom_table_ensure_atom(table, (const uint8_t *) "decimals", 8, AtomTableNoOpts, &new_index); assert(r == AtomTableEnsureAtomOk); assert(new_index == decimals_index);