Skip to content

Commit 529ddf2

Browse files
committed
Update atom_table API and allow for longer atoms
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent 7960a7d commit 529ddf2

File tree

23 files changed

+558
-583
lines changed

23 files changed

+558
-583
lines changed

src/libAtomVM/atom_table.c

Lines changed: 95 additions & 142 deletions
Large diffs are not rendered by default.

src/libAtomVM/atom_table.h

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929
extern "C" {
3030
#endif
3131

32-
#define ATOM_TABLE_NOT_FOUND -1
33-
#define ATOM_TABLE_ALLOC_FAIL -2
34-
#define ATOM_TABLE_INVALID_LEN -3
32+
#define ATOM_TABLE_NOT_FOUND ((AtomIndex) -1)
33+
#define ATOM_TABLE_ALLOC_FAIL ((AtomIndex) -2)
3534

3635
struct AtomTable;
3736

@@ -48,31 +47,75 @@ enum AtomTableCopyOpt
4847
AtomTableAlreadyExisting = 2
4948
};
5049

50+
enum AtomTableEnsureAtomsResult
51+
{
52+
AtomTableEnsureAtomsOk = 0,
53+
AtomTableEnsureAtomsAllocFail = -2,
54+
AtomTableEnsureAtomsInvalidLen = -3,
55+
};
56+
5157
typedef const void *atom_ref_t;
5258

5359
struct AtomTable *atom_table_new();
5460
void atom_table_destroy(struct AtomTable *table);
5561

5662
size_t atom_table_count(struct AtomTable *table);
5763

58-
long atom_table_ensure_atom(struct AtomTable *table, AtomString string, enum AtomTableCopyOpt opts);
59-
60-
// This function is deprecated and it will be removed.
61-
// atom strings should be copied to caller owned buffers.
62-
AtomString atom_table_get_atom_string(struct AtomTable *table, long index);
64+
AtomIndex atom_table_ensure_atom(struct AtomTable *table, const uint8_t *atom_data, size_t atom_len, enum AtomTableCopyOpt opts);
6365

64-
long atom_table_get_index(struct AtomTable *table, AtomString string);
66+
AtomIndex atom_table_get_index(struct AtomTable *table, AtomString string);
67+
AtomIndex atom_table_get_index_from_cstring(struct AtomTable *table, const char *name);
6568

66-
int atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, int count,
67-
int *translate_table, enum EnsureAtomsOpt opts);
69+
enum AtomTableEnsureAtomsResult atom_table_ensure_atoms(struct AtomTable *table, const void *atoms, size_t count,
70+
AtomIndex *translate_table, enum EnsureAtomsOpt opts);
6871

72+
bool atom_table_is_equal_to_atom_string(
73+
struct AtomTable *table, AtomIndex t_atom_index, AtomString atom_string);
6974
int atom_table_cmp_using_atom_index(
70-
struct AtomTable *table, int t_atom_index, int other_atom_index);
71-
atom_ref_t atom_table_get_atom_ptr_and_len(struct AtomTable *table, long index, size_t *out_len);
72-
bool atom_table_is_atom_ref_ascii(struct AtomTable *table, atom_ref_t atom);
73-
void atom_table_write_bytes(struct AtomTable *table, atom_ref_t atom, size_t buf_len, void *outbuf);
74-
void atom_table_write_cstring(
75-
struct AtomTable *table, atom_ref_t atom, size_t buf_len, char *outbuf);
75+
struct AtomTable *table, AtomIndex t_atom_index, AtomIndex other_atom_index);
76+
77+
/**
78+
* @brief Allocate a new C string with malloc with the representation of
79+
* an atom
80+
*
81+
* @param table atom table
82+
* @param atom_index index of the atom to get the representation of
83+
* @return a newly allocated string with the representation of the atom or
84+
* NULL if allocation failed or atom index doesn't exist
85+
*/
86+
char *atom_table_atom_to_new_cstring(struct AtomTable *table, AtomIndex atom_index);
87+
88+
/**
89+
* @brief Get a pointer to the character data of a given atom.
90+
*
91+
* @details returned pointer is not null terminated
92+
*
93+
* @param table atom table
94+
* @param atom_index index of the atom to get the representation of
95+
* @param out_len on output, size of the character data
96+
*/
97+
const uint8_t *atom_table_get_atom_string(struct AtomTable *table, AtomIndex index, size_t *out_len);
98+
99+
/**
100+
* @brief Write module:function/arity to the supplied buffer.
101+
*
102+
* @details Write module:function/arity to the supplied buffer. This function will abort
103+
* if the written module, function, and arity are longer than the supplied
104+
* buffer size.
105+
* @param buf the buffer to write into
106+
* @param buf_size the amount of room in the buffer
107+
* @param module the module name
108+
* @param function the function name
109+
* @param arity the function arity
110+
*/
111+
static inline void atom_table_write_mfa(struct AtomTable *table, char *buf, size_t buf_size, AtomIndex module, AtomIndex function, unsigned int arity)
112+
{
113+
size_t module_name_len;
114+
const uint8_t *module_name = atom_table_get_atom_string(table, module, &module_name_len);
115+
size_t function_name_len;
116+
const uint8_t *function_name = atom_table_get_atom_string(table, function, &function_name_len);
117+
atom_write_mfa(buf, buf_size, module_name_len, module_name, function_name_len, function_name, arity);
118+
}
76119

77120
#ifdef __cplusplus
78121
}

src/libAtomVM/bif.c

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,34 +1579,30 @@ static term list_to_atom(Context *ctx, term a_list, bool create_new, term *error
15791579
}
15801580

15811581
int ok;
1582-
char *atom_string = interop_list_to_utf8_string(a_list, &ok);
1582+
avm_int_t len = term_list_length(a_list, &ok);
15831583
if (UNLIKELY(!ok)) {
1584-
*error_reason = OUT_OF_MEMORY_ATOM;
1584+
*error_reason = BADARG_ATOM;
15851585
return term_invalid_term();
15861586
}
1587-
int atom_string_len = strlen(atom_string);
1588-
if (UNLIKELY(atom_string_len > 255)) {
1589-
free(atom_string);
1587+
if (len > 255) {
15901588
*error_reason = SYSTEM_LIMIT_ATOM;
15911589
return term_invalid_term();
15921590
}
15931591

1594-
AtomString atom = malloc(atom_string_len + 1);
1595-
if (IS_NULL_PTR(atom)) {
1596-
free(atom_string);
1592+
char *atom_string = interop_list_to_utf8_string(a_list, &ok);
1593+
if (UNLIKELY(!ok)) {
15971594
*error_reason = OUT_OF_MEMORY_ATOM;
15981595
return term_invalid_term();
15991596
}
1600-
((uint8_t *) atom)[0] = atom_string_len;
1601-
memcpy(((char *) atom) + 1, atom_string, atom_string_len);
1602-
free(atom_string);
1597+
size_t atom_string_len = strlen(atom_string);
16031598

16041599
enum AtomTableCopyOpt atom_opts = AtomTableCopyAtom;
16051600
if (!create_new) {
16061601
atom_opts |= AtomTableAlreadyExisting;
16071602
}
1608-
long global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts);
1609-
free((void *) atom);
1603+
AtomIndex global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, (const uint8_t *) atom_string, atom_string_len, atom_opts);
1604+
free(atom_string);
1605+
16101606
if (UNLIKELY(global_atom_index == ATOM_TABLE_NOT_FOUND)) {
16111607
*error_reason = BADARG_ATOM;
16121608
return term_invalid_term();
@@ -1650,10 +1646,6 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new,
16501646

16511647
const char *atom_string = term_binary_data(a_binary);
16521648
size_t atom_string_len = term_binary_size(a_binary);
1653-
if (UNLIKELY(atom_string_len > 255)) {
1654-
*error_reason = SYSTEM_LIMIT_ATOM;
1655-
return term_invalid_term();
1656-
}
16571649

16581650
bool encode_latin1_to_utf8 = false;
16591651
if (UNLIKELY((encoding == LATIN1_ATOM)
@@ -1665,48 +1657,50 @@ term binary_to_atom(Context *ctx, term a_binary, term encoding, bool create_new,
16651657
return term_invalid_term();
16661658
}
16671659

1668-
AtomString atom;
1660+
const uint8_t *atom_data;
1661+
size_t atom_data_len;
1662+
uint8_t *buf = NULL;
16691663
if (LIKELY(!encode_latin1_to_utf8)) {
16701664
if (UNLIKELY(!unicode_is_valid_utf8_buf((const uint8_t *) atom_string, atom_string_len))) {
16711665
*error_reason = BADARG_ATOM;
16721666
return term_invalid_term();
16731667
}
1674-
atom = malloc(atom_string_len + 1);
1675-
if (IS_NULL_PTR(atom)) {
1676-
*error_reason = OUT_OF_MEMORY_ATOM;
1668+
size_t len = unicode_buf_utf8_len((const uint8_t *) atom_string, atom_string_len);
1669+
if (UNLIKELY(len > 255)) {
1670+
*error_reason = SYSTEM_LIMIT_ATOM;
16771671
return term_invalid_term();
16781672
}
1679-
((uint8_t *) atom)[0] = atom_string_len;
1680-
memcpy(((char *) atom) + 1, atom_string, atom_string_len);
1673+
1674+
atom_data = (const uint8_t *) atom_string;
1675+
atom_data_len = atom_string_len;
16811676
} else {
1677+
if (UNLIKELY(atom_string_len > 255)) {
1678+
*error_reason = SYSTEM_LIMIT_ATOM;
1679+
return term_invalid_term();
1680+
}
1681+
16821682
// * 2 is the worst case size
16831683
size_t buf_len = atom_string_len * 2;
1684-
atom = malloc(buf_len + 1);
1685-
if (IS_NULL_PTR(atom)) {
1684+
buf = malloc(buf_len);
1685+
if (IS_NULL_PTR(buf)) {
16861686
*error_reason = OUT_OF_MEMORY_ATOM;
16871687
return term_invalid_term();
16881688
}
1689-
uint8_t *atom_data = ((uint8_t *) atom) + 1;
1690-
size_t out_pos = 0;
1689+
atom_data = buf;
1690+
atom_data_len = 0;
16911691
for (size_t i = 0; i < atom_string_len; i++) {
16921692
size_t out_size;
1693-
bitstring_utf8_encode(((uint8_t) atom_string[i]), &atom_data[out_pos], &out_size);
1694-
out_pos += out_size;
1695-
}
1696-
if (out_pos > 255) {
1697-
free((void *) atom);
1698-
*error_reason = SYSTEM_LIMIT_ATOM;
1699-
return term_invalid_term();
1693+
bitstring_utf8_encode(((uint8_t) atom_string[i]), &buf[atom_data_len], &out_size);
1694+
atom_data_len += out_size;
17001695
}
1701-
((uint8_t *) atom)[0] = out_pos;
17021696
}
17031697

17041698
enum AtomTableCopyOpt atom_opts = AtomTableCopyAtom;
17051699
if (!create_new) {
17061700
atom_opts |= AtomTableAlreadyExisting;
17071701
}
1708-
long global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, atom, atom_opts);
1709-
free((void *) atom);
1702+
AtomIndex global_atom_index = atom_table_ensure_atom(ctx->global->atom_table, atom_data, atom_data_len, atom_opts);
1703+
free(buf);
17101704
if (UNLIKELY(global_atom_index == ATOM_TABLE_NOT_FOUND)) {
17111705
*error_reason = BADARG_ATOM;
17121706
return term_invalid_term();

src/libAtomVM/ets_hashtable.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,8 @@ bool ets_hashtable_remove(struct EtsHashTable *hash_table, term key, size_t keyp
241241

242242
static uint32_t hash_atom(term t, int32_t h, GlobalContext *global)
243243
{
244-
AtomString atom_str = (uint8_t *) globalcontext_atomstring_from_term(global, t);
245-
size_t len = atom_string_len(atom_str);
246-
const uint8_t *data = (const uint8_t *) atom_string_data(atom_str);
244+
size_t len;
245+
const uint8_t *data = atom_table_get_atom_string(global->atom_table, term_to_atom_index(t), &len);
247246
for (size_t i = 0; i < len; ++i) {
248247
h = h * LARGE_PRIME_ATOM + data[i];
249248
}

src/libAtomVM/exportedfunction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ struct Nif
9393
struct UnresolvedFunctionCall
9494
{
9595
struct ExportedFunction base;
96-
int module_atom_index;
97-
int function_atom_index;
96+
AtomIndex module_atom_index;
97+
AtomIndex function_atom_index;
9898
int arity;
9999
};
100100

src/libAtomVM/globalcontext.c

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -570,22 +570,7 @@ term globalcontext_get_registered_name_process(GlobalContext *glb, int local_pro
570570

571571
bool globalcontext_is_atom_index_equal_to_atom_string(GlobalContext *glb, AtomIndex atom_index_a, AtomString atom_string_b)
572572
{
573-
AtomString atom_string_a;
574-
atom_string_a = atom_table_get_atom_string(glb->atom_table, atom_index_a);
575-
return atom_are_equals(atom_string_a, atom_string_b);
576-
}
577-
578-
AtomString globalcontext_atomstring_from_term(GlobalContext *glb, term t)
579-
{
580-
if (!term_is_atom(t)) {
581-
AVM_ABORT();
582-
}
583-
unsigned long atom_index = term_to_atom_index(t);
584-
AtomString str = atom_table_get_atom_string(glb->atom_table, atom_index);
585-
if (IS_NULL_PTR(str)) {
586-
return NULL;
587-
}
588-
return str;
573+
return atom_table_is_equal_to_atom_string(glb->atom_table, atom_index_a, atom_string_b);
589574
}
590575

591576
term globalcontext_existing_term_from_atom_string(GlobalContext *glb, AtomString atom_string)
@@ -662,28 +647,30 @@ Module *globalcontext_get_module(GlobalContext *global, AtomIndex module_name_at
662647
Module *found_module = (Module *) atomshashtable_get_value(global->modules_table, module_name_atom, (unsigned long) NULL);
663648

664649
if (!found_module) {
665-
char *module_name = malloc(256 + 5);
666-
if (IS_NULL_PTR(module_name)) {
650+
size_t module_name_len;
651+
const uint8_t *module_name = atom_table_get_atom_string(global->atom_table, module_name_atom, &module_name_len);
652+
653+
char *module_file_name = malloc(module_name_len + 6);
654+
if (IS_NULL_PTR(module_file_name)) {
667655
return NULL;
668656
}
669-
670-
atom_string_to_c(module_name_atom, module_name, 256);
671-
strcat(module_name, ".beam");
672-
Module *loaded_module = globalcontext_load_module_from_avm(global, module_name);
657+
memcpy(module_file_name, module_name, module_name_len);
658+
memcpy(module_file_name + module_name_len, ".beam", 6);
659+
Module *loaded_module = globalcontext_load_module_from_avm(global, module_file_name);
673660
if (IS_NULL_PTR(loaded_module)) {
674661
// Platform may implement sys_load_module_from_file
675-
loaded_module = sys_load_module_from_file(global, module_name);
662+
loaded_module = sys_load_module_from_file(global, module_file_name);
676663
}
677664
if (UNLIKELY(!loaded_module || (globalcontext_insert_module(global, loaded_module) < 0))) {
678-
fprintf(stderr, "Failed load module: %s\n", module_name);
679-
free(module_name);
665+
fprintf(stderr, "Failed load module: %s\n", module_file_name);
666+
free(module_file_name);
680667
if (loaded_module) {
681668
module_destroy(loaded_module);
682669
}
683670
return NULL;
684671
}
685672

686-
free(module_name);
673+
free(module_file_name);
687674

688675
return loaded_module;
689676
}

src/libAtomVM/globalcontext.h

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -357,22 +357,22 @@ void globalcontext_maybe_unregister_process_id(GlobalContext *glb, int process_i
357357
* assumes "ownership" of the allocated memory.
358358
* @returns newly added atom id or -1 in case of failure.
359359
*/
360-
static inline int globalcontext_insert_atom_maybe_copy(GlobalContext *glb, AtomString atom_string, int copy)
360+
static inline int globalcontext_insert_atom_maybe_copy(GlobalContext *glb, const uint8_t *atom_data, size_t atom_len, int copy)
361361
{
362-
long index = atom_table_ensure_atom(
363-
glb->atom_table, atom_string, copy ? AtomTableCopyAtom : AtomTableNoOpts);
362+
int index = atom_table_ensure_atom(
363+
glb->atom_table, atom_data, atom_len, copy ? AtomTableCopyAtom : AtomTableNoOpts);
364364
if (UNLIKELY(index) < 0) {
365365
return -1;
366366
}
367367
return index;
368368
}
369369

370370
/**
371-
* @brief equivalent to globalcontext_insert_atom_maybe_copy(glb, atom_string, 0);
371+
* @brief equivalent to globalcontext_insert_atom_maybe_copy(glb, atom_string_data(atom_string), atom_string_len(atom_string), 0);
372372
*/
373373
static inline int globalcontext_insert_atom(GlobalContext *glb, AtomString atom_string)
374374
{
375-
return globalcontext_insert_atom_maybe_copy(glb, atom_string, 0);
375+
return globalcontext_insert_atom_maybe_copy(glb, atom_string_data(atom_string), atom_string_len(atom_string), 0);
376376
}
377377

378378
/**
@@ -420,20 +420,6 @@ static inline term globalcontext_make_atom(GlobalContext *glb, AtomString string
420420
return term_from_atom_index(global_atom_index);
421421
}
422422

423-
/**
424-
* @brief Returns the AtomString value of a term.
425-
*
426-
* @details This function fetches the AtomString value of the atom associated
427-
* with the supplied term. The input term must be an atom type.
428-
* If no such atom is registered in the global table, this function
429-
* returns NULL. The caller should NOT free the data associated with
430-
* the returned value.
431-
* @param glb the global context
432-
* @param t the atom term
433-
* @returns the AtomString associated with the supplied atom term.
434-
*/
435-
AtomString globalcontext_atomstring_from_term(GlobalContext *glb, term t);
436-
437423
/**
438424
* @brief Returns the term for an existing atom.
439425
*

src/libAtomVM/interop.c

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,7 @@ char *interop_list_to_utf8_string(term list, int *ok)
197197
char *interop_atom_to_string(Context *ctx, term atom)
198198
{
199199
GlobalContext *glb = ctx->global;
200-
201-
int atom_index = term_to_atom_index(atom);
202-
203-
size_t len;
204-
atom_ref_t atom_ref = atom_table_get_atom_ptr_and_len(glb->atom_table, atom_index, &len);
205-
206-
char *str = malloc(len + 1);
207-
if (IS_NULL_PTR(str)) {
208-
return NULL;
209-
}
210-
atom_table_write_cstring(glb->atom_table, atom_ref, len + 1, str);
211-
212-
return str;
200+
return atom_table_atom_to_new_cstring(glb->atom_table, term_to_atom_index(atom));
213201
}
214202

215203
term interop_proplist_get_value(term list, term key)

0 commit comments

Comments
 (0)