Skip to content

Commit 29943ee

Browse files
committed
Merge pull request #1654 from pguyot/w19/reduce-line-ref-memory-footprint
Reduce memory footprint of line refs These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents 670c9fd + 39acce4 commit 29943ee

File tree

3 files changed

+88
-44
lines changed

3 files changed

+88
-44
lines changed

src/libAtomVM/module.c

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ static void module_add_label(Module *mod, int index, const uint8_t *ptr);
5757
static enum ModuleLoadResult module_build_imported_functions_table(Module *this_module, uint8_t *table_data, GlobalContext *glb);
5858
static void module_parse_line_table(Module *mod, const uint8_t *data, size_t len);
5959

60+
struct LineRefOffset
61+
{
62+
struct ListHead head;
63+
unsigned int offset;
64+
};
65+
6066
#define IMPL_CODE_LOADER 1
6167
#include "opcodesswitch.h"
6268
#undef TRACE
@@ -276,7 +282,6 @@ Module *module_new_from_iff_binary(GlobalContext *global, const void *iff_binary
276282
}
277283

278284
module_parse_line_table(mod, beam_file + offsets[LINT] + 8, sizes[LINT]);
279-
list_init(&mod->line_ref_offsets);
280285

281286
if (offsets[LITT]) {
282287
#ifdef WITH_ZLIB
@@ -305,7 +310,40 @@ Module *module_new_from_iff_binary(GlobalContext *global, const void *iff_binary
305310
mod->free_literals_data = 0;
306311
}
307312

308-
mod->end_instruction_ii = read_core_chunk(mod);
313+
struct ListHead line_refs;
314+
list_init(&line_refs);
315+
mod->end_instruction_ii = read_core_chunk(mod, &line_refs);
316+
317+
// Create the list of offsets if the module has line informations.
318+
if (mod->line_refs_table != NULL) {
319+
// Compute the size of the list
320+
size_t num_offsets = 0;
321+
struct ListHead *item = line_refs.next;
322+
while (item != &line_refs) {
323+
num_offsets++;
324+
item = item->next;
325+
}
326+
mod->line_refs_offsets = malloc(num_offsets * sizeof(unsigned int));
327+
if (IS_NULL_PTR(mod->line_refs_offsets)) {
328+
fprintf(stderr, "Warning: Unable to allocate space for line refs offset, module has %zu offsets. Line information in stacktraces may be missing\n", num_offsets);
329+
} else {
330+
size_t index = 0;
331+
item = line_refs.next;
332+
while (item != &line_refs) {
333+
struct LineRefOffset *offset = CONTAINER_OF(item, struct LineRefOffset, head);
334+
mod->line_refs_offsets[index] = offset->offset;
335+
index++;
336+
item = item->next;
337+
}
338+
mod->line_refs_offsets_count = num_offsets;
339+
}
340+
}
341+
// Empty the list
342+
while (!list_is_empty(&line_refs)) {
343+
struct ListHead *item = line_refs.next;
344+
list_remove(item);
345+
free(item);
346+
}
309347

310348
return mod;
311349
}
@@ -316,6 +354,7 @@ COLD_FUNC void module_destroy(Module *module)
316354
free(module->imported_funcs);
317355
free(module->literals_table);
318356
free(module->local_atoms_to_global_table);
357+
free(module->line_refs_offsets);
319358
if (module->free_literals_data) {
320359
free(module->literals_data);
321360
}
@@ -697,19 +736,28 @@ static void module_parse_line_table(Module *mod, const uint8_t *data, size_t len
697736
}
698737
}
699738

700-
void module_insert_line_ref_offset(Module *mod, int line_ref, int offset)
739+
void module_insert_line_ref_offset(Module *mod, struct ListHead *line_refs, uint32_t line_ref, int offset)
701740
{
702741
if (IS_NULL_PTR(mod->line_refs_table) || line_ref == 0) {
703742
return;
704743
}
705744
struct LineRefOffset *ref_offset = malloc(sizeof(struct LineRefOffset));
706745
if (IS_NULL_PTR(ref_offset)) {
707-
fprintf(stderr, "Warning: Unable to allocate space for line ref offset. Line information in stacktraces may be missing\n");
746+
size_t num_refs = 0;
747+
// Empty the list
748+
while (!list_is_empty(line_refs)) {
749+
struct ListHead *item = line_refs->next;
750+
list_remove(item);
751+
free(item);
752+
num_refs++;
753+
}
754+
fprintf(stderr, "Warning: Unable to allocate space for an additional line ref offset (we had %zu). Line information in stacktraces may be missing\n", num_refs);
755+
// Give up having line numbers for this module.
756+
mod->line_refs_table = NULL;
708757
return;
709758
}
710-
ref_offset->line_ref = line_ref;
711759
ref_offset->offset = offset;
712-
list_append(&mod->line_ref_offsets, &ref_offset->head);
760+
list_append(line_refs, &ref_offset->head);
713761
}
714762

715763
static bool module_find_line_ref(Module *mod, uint16_t line_ref, uint32_t *line, size_t *filename_len, const uint8_t **filename)
@@ -723,30 +771,30 @@ static bool module_find_line_ref(Module *mod, uint16_t line_ref, uint32_t *line,
723771

724772
bool module_find_line(Module *mod, unsigned int offset, uint32_t *line, size_t *filename_len, const uint8_t **filename)
725773
{
726-
int i = 0;
727-
struct LineRefOffset *head = GET_LIST_ENTRY(&mod->line_ref_offsets, struct LineRefOffset, head);
728-
struct ListHead *item;
729-
LIST_FOR_EACH (item, &mod->line_ref_offsets) {
730-
struct LineRefOffset *ref_offset = GET_LIST_ENTRY(item, struct LineRefOffset, head);
731-
732-
if (offset == ref_offset->offset) {
733-
return module_find_line_ref(mod, ref_offset->line_ref, line, filename_len, filename);
734-
} else if (i == 0 && offset < ref_offset->offset) {
774+
size_t i;
775+
unsigned int ref_offset;
776+
uint32_t line_ref;
777+
const uint8_t *ref_pc;
778+
if (IS_NULL_PTR(mod->line_refs_offsets)) {
779+
return false;
780+
}
781+
for (i = 0; i < mod->line_refs_offsets_count; i++) {
782+
ref_offset = mod->line_refs_offsets[i];
783+
if (offset == ref_offset) {
784+
ref_pc = &mod->code->code[ref_offset];
785+
DECODE_LITERAL(line_ref, ref_pc);
786+
return module_find_line_ref(mod, line_ref, line, filename_len, filename);
787+
} else if (i == 0 && offset < ref_offset) {
735788
return false;
736-
} else {
737-
738-
struct LineRefOffset *prev_ref_offset = GET_LIST_ENTRY(ref_offset->head.prev, struct LineRefOffset, head);
739-
if (prev_ref_offset->offset <= offset && offset < ref_offset->offset) {
740-
return module_find_line_ref(mod, prev_ref_offset->line_ref, line, filename_len, filename);
741-
}
742-
743-
struct LineRefOffset *next_ref_offset = GET_LIST_ENTRY(ref_offset->head.next, struct LineRefOffset, head);
744-
if (next_ref_offset == head && ref_offset->offset <= offset) {
745-
return module_find_line_ref(mod, ref_offset->line_ref, line, filename_len, filename);
746-
}
789+
} else if (offset < ref_offset) {
790+
ref_offset = mod->line_refs_offsets[i - 1];
791+
ref_pc = &mod->code->code[ref_offset];
792+
DECODE_LITERAL(line_ref, ref_pc);
793+
return module_find_line_ref(mod, line_ref, line, filename_len, filename);
747794
}
748-
749-
++i;
750795
}
751-
return false;
796+
ref_offset = mod->line_refs_offsets[i - 1];
797+
ref_pc = &mod->code->code[ref_offset];
798+
DECODE_LITERAL(line_ref, ref_pc);
799+
return module_find_line_ref(mod, line_ref, line, filename_len, filename);
752800
}

src/libAtomVM/module.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,6 @@ struct ModuleFilename
8888
size_t len;
8989
};
9090

91-
struct LineRefOffset
92-
{
93-
struct ListHead head;
94-
unsigned int offset;
95-
uint16_t line_ref;
96-
};
97-
9891
struct Module
9992
{
10093
#ifdef ENABLE_ADVANCED_TRACE
@@ -113,7 +106,8 @@ struct Module
113106
size_t locations_count;
114107
const uint8_t *locations_table;
115108

116-
struct ListHead line_ref_offsets;
109+
unsigned int *line_refs_offsets;
110+
size_t line_refs_offsets_count;
117111

118112
const struct ExportedFunction **imported_funcs;
119113

@@ -390,10 +384,11 @@ bool module_get_function_from_label(Module *this_module, int label, AtomString *
390384
* is a no-op.
391385
*
392386
* @param mod the module
387+
* @param line_refs the list of line references to append to
393388
* @param line_ref the line reference (index)
394389
* @param offset the instruction offset at which the line instruction occurred.
395390
*/
396-
void module_insert_line_ref_offset(Module *mod, int line_ref, int offset);
391+
void module_insert_line_ref_offset(Module *mod, struct ListHead *line_refs, uint32_t line_ref, int offset);
397392

398393
/*
399394
* @brief Find the latest line reference (index) before or at which the instruction offset

src/libAtomVM/opcodesswitch.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,9 +1809,9 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
18091809
#endif
18101810

18111811
#ifdef IMPL_CODE_LOADER
1812-
int read_core_chunk0(Module *mod);
1812+
int read_core_chunk0(Module *mod, struct ListHead *line_refs);
18131813

1814-
int read_core_chunk(Module *mod)
1814+
int read_core_chunk(Module *mod, struct ListHead *line_refs)
18151815
#else
18161816
#ifdef IMPL_EXECUTE_LOOP
18171817
int context_execute_loop(Context *ctx, Module *mod, const char *function_name, int arity)
@@ -1848,7 +1848,7 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
18481848
#endif
18491849

18501850
#ifdef IMPL_CODE_LOADER
1851-
return read_core_chunk0(mod);
1851+
return read_core_chunk0(mod, line_refs);
18521852
#endif
18531853
#ifdef IMPL_EXECUTE_LOOP
18541854
// This process is the first scheduler process
@@ -1860,7 +1860,7 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
18601860
}
18611861

18621862
#ifdef IMPL_CODE_LOADER
1863-
int read_core_chunk0(Module *mod)
1863+
int read_core_chunk0(Module *mod, struct ListHead *line_refs)
18641864
#else
18651865
#ifdef IMPL_EXECUTE_LOOP
18661866
HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
@@ -5675,15 +5675,16 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
56755675

56765676
case OP_LINE: {
56775677
#ifdef IMPL_CODE_LOADER
5678-
const uint8_t *saved_pc = pc -1;
5678+
unsigned int offset = pc - code;
56795679
#endif
56805680
uint32_t line_number;
5681+
// This decode increments pc and ensures we can decode it
56815682
DECODE_LITERAL(line_number, pc);
56825683

56835684
TRACE("line/1: %i\n", line_number);
56845685

56855686
#ifdef IMPL_CODE_LOADER
5686-
module_insert_line_ref_offset(mod, line_number, saved_pc - code);
5687+
module_insert_line_ref_offset(mod, line_refs, line_number, offset);
56875688
#endif
56885689
break;
56895690
}

0 commit comments

Comments
 (0)