Skip to content

Commit 88ab79d

Browse files
committed
Optimize memory_scan_and_copy and memory_scan_and_rewrite
Replace slow tests with various immediates with a test on the `TERM_PRIMARY_MASK` bits. Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent a9b0e7d commit 88ab79d

File tree

2 files changed

+151
-182
lines changed

2 files changed

+151
-182
lines changed

src/libAtomVM/memory.c

Lines changed: 150 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -580,137 +580,121 @@ static void memory_scan_and_copy(HeapFragment *old_fragment, term *mem_start, co
580580

581581
while (ptr < mem_end) {
582582
term t = *ptr;
583+
switch (t & TERM_PRIMARY_MASK) {
584+
case TERM_PRIMARY_IMMED:
585+
TRACE("Found immediate (%" TERM_X_FMT ")\n", t);
586+
ptr++;
587+
break;
588+
case TERM_PRIMARY_CP: {
589+
TRACE("Found boxed header (%" TERM_X_FMT ")\n", t);
590+
591+
size_t arity = term_get_size_from_boxed_header(t);
592+
switch (t & TERM_BOXED_TAG_MASK) {
593+
case TERM_BOXED_TUPLE: {
594+
TRACE("- Boxed is tuple (%" TERM_X_FMT "), arity: %i\n", t, (int) arity);
595+
596+
for (size_t i = 1; i <= arity; i++) {
597+
TRACE("-- Elem: %" TERM_X_FMT "\n", ptr[i]);
598+
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
599+
}
600+
break;
601+
}
583602

584-
if (term_is_atom(t)) {
585-
TRACE("Found atom (%" TERM_X_FMT ")\n", t);
586-
ptr++;
587-
588-
} else if (term_is_integer(t)) {
589-
TRACE("Found integer (%" TERM_X_FMT ")\n", t);
590-
ptr++;
591-
592-
} else if (term_is_nil(t)) {
593-
TRACE("Found NIL (%" TERM_X_FMT ")\n", t);
594-
ptr++;
595-
596-
} else if (term_is_local_pid(t)) {
597-
TRACE("Found PID (%" TERM_X_FMT ")\n", t);
598-
ptr++;
599-
600-
} else if (term_is_local_port(t)) {
601-
TRACE("Found port (%" TERM_X_FMT ")\n", t);
602-
ptr++;
603-
604-
} else if ((t & 0x3) == 0x0) {
605-
TRACE("Found boxed header (%" TERM_X_FMT ")\n", t);
606-
607-
size_t arity = term_get_size_from_boxed_header(t);
608-
switch (t & TERM_BOXED_TAG_MASK) {
609-
case TERM_BOXED_TUPLE: {
610-
TRACE("- Boxed is tuple (%" TERM_X_FMT "), arity: %i\n", t, (int) arity);
611-
612-
for (size_t i = 1; i <= arity; i++) {
613-
TRACE("-- Elem: %" TERM_X_FMT "\n", ptr[i]);
614-
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
603+
case TERM_BOXED_BIN_MATCH_STATE: {
604+
TRACE("- Found bin match state.\n");
605+
ptr[1] = memory_shallow_copy_term(old_fragment, ptr[1], &new_heap, move);
606+
break;
615607
}
616-
break;
617-
}
618608

619-
case TERM_BOXED_BIN_MATCH_STATE: {
620-
TRACE("- Found bin match state.\n");
621-
ptr[1] = memory_shallow_copy_term(old_fragment, ptr[1], &new_heap, move);
622-
break;
623-
}
609+
case TERM_BOXED_POSITIVE_INTEGER:
610+
TRACE("- Found boxed pos int.\n");
611+
break;
624612

625-
case TERM_BOXED_POSITIVE_INTEGER:
626-
TRACE("- Found boxed pos int.\n");
627-
break;
613+
case TERM_BOXED_REF:
614+
TRACE("- Found ref.\n");
615+
break;
628616

629-
case TERM_BOXED_REF:
630-
TRACE("- Found ref.\n");
631-
break;
617+
case TERM_BOXED_EXTERNAL_PID:
618+
TRACE("- Found external pid.\n");
619+
break;
632620

633-
case TERM_BOXED_EXTERNAL_PID:
634-
TRACE("- Found external pid.\n");
635-
break;
621+
case TERM_BOXED_EXTERNAL_PORT:
622+
TRACE("- Found external port.\n");
623+
break;
636624

637-
case TERM_BOXED_EXTERNAL_PORT:
638-
TRACE("- Found external port.\n");
639-
break;
625+
case TERM_BOXED_EXTERNAL_REF:
626+
TRACE("- Found external ref.\n");
627+
break;
640628

641-
case TERM_BOXED_EXTERNAL_REF:
642-
TRACE("- Found external ref.\n");
643-
break;
644-
645-
case TERM_BOXED_FUN: {
646-
TRACE("- Found fun, size: %i.\n", (int) arity);
629+
case TERM_BOXED_FUN: {
630+
TRACE("- Found fun, size: %i.\n", (int) arity);
647631

648-
// first term is the boxed header, followed by module and fun index.
632+
// first term is the boxed header, followed by module and fun index.
649633

650-
for (size_t i = 3; i <= arity; i++) {
651-
TRACE("-- Frozen: %" TERM_X_FMT "\n", ptr[i]);
652-
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
634+
for (size_t i = 3; i <= arity; i++) {
635+
TRACE("-- Frozen: %" TERM_X_FMT "\n", ptr[i]);
636+
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
637+
}
638+
break;
653639
}
654-
break;
655-
}
656640

657-
case TERM_BOXED_FLOAT:
658-
TRACE("- Found float.\n");
659-
break;
641+
case TERM_BOXED_FLOAT:
642+
TRACE("- Found float.\n");
643+
break;
644+
645+
case TERM_BOXED_REFC_BINARY: {
646+
TRACE("- Found refc binary.\n");
647+
term ref = ((term) ptr) | TERM_PRIMARY_BOXED;
648+
if (!term_refc_binary_is_const(ref)) {
649+
*mso_list = term_list_init_prepend(ptr + REFC_BINARY_CONS_OFFSET, ref, *mso_list);
650+
refc_binary_increment_refcount((struct RefcBinary *) term_refc_binary_ptr(ref));
651+
}
652+
break;
653+
}
660654

661-
case TERM_BOXED_REFC_BINARY: {
662-
TRACE("- Found refc binary.\n");
663-
term ref = ((term) ptr) | TERM_PRIMARY_BOXED;
664-
if (!term_refc_binary_is_const(ref)) {
665-
*mso_list = term_list_init_prepend(ptr + REFC_BINARY_CONS_OFFSET, ref, *mso_list);
666-
refc_binary_increment_refcount((struct RefcBinary *) term_refc_binary_ptr(ref));
655+
case TERM_BOXED_SUB_BINARY: {
656+
TRACE("- Found sub binary.\n");
657+
ptr[3] = memory_shallow_copy_term(old_fragment, ptr[3], &new_heap, move);
658+
break;
667659
}
668-
break;
669-
}
670660

671-
case TERM_BOXED_SUB_BINARY: {
672-
TRACE("- Found sub binary.\n");
673-
ptr[3] = memory_shallow_copy_term(old_fragment, ptr[3], &new_heap, move);
674-
break;
661+
case TERM_BOXED_HEAP_BINARY:
662+
TRACE("- Found binary.\n");
663+
break;
664+
665+
case TERM_BOXED_MAP: {
666+
TRACE("- Found map.\n");
667+
size_t map_size = arity - 1;
668+
size_t keys_offset = term_get_map_keys_offset();
669+
size_t value_offset = term_get_map_value_offset();
670+
TRACE("-- Map keys: %" TERM_X_FMT "\n", ptr[keys_offset]);
671+
ptr[keys_offset] = memory_shallow_copy_term(old_fragment, ptr[keys_offset], &new_heap, move);
672+
for (size_t i = value_offset; i < value_offset + map_size; ++i) {
673+
TRACE("-- Map Value: %" TERM_X_FMT "\n", ptr[i]);
674+
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
675+
}
676+
} break;
677+
678+
default:
679+
fprintf(stderr, "- Found unknown boxed type: %" TERM_X_FMT "\n", (t >> 2) & 0xF);
680+
AVM_ABORT();
675681
}
676682

677-
case TERM_BOXED_HEAP_BINARY:
678-
TRACE("- Found binary.\n");
679-
break;
680-
681-
case TERM_BOXED_MAP: {
682-
TRACE("- Found map.\n");
683-
size_t map_size = arity - 1;
684-
size_t keys_offset = term_get_map_keys_offset();
685-
size_t value_offset = term_get_map_value_offset();
686-
TRACE("-- Map keys: %" TERM_X_FMT "\n", ptr[keys_offset]);
687-
ptr[keys_offset] = memory_shallow_copy_term(old_fragment, ptr[keys_offset], &new_heap, move);
688-
for (size_t i = value_offset; i < value_offset + map_size; ++i) {
689-
TRACE("-- Map Value: %" TERM_X_FMT "\n", ptr[i]);
690-
ptr[i] = memory_shallow_copy_term(old_fragment, ptr[i], &new_heap, move);
691-
}
692-
} break;
693-
694-
default:
695-
fprintf(stderr, "- Found unknown boxed type: %" TERM_X_FMT "\n", (t >> 2) & 0xF);
696-
AVM_ABORT();
683+
ptr += arity + 1;
684+
break;
697685
}
698-
699-
ptr += arity + 1;
700-
701-
} else if (term_is_nonempty_list(t)) {
702-
TRACE("Found nonempty list (%p)\n", (void *) t);
703-
*ptr = memory_shallow_copy_term(old_fragment, t, &new_heap, move);
704-
ptr++;
705-
706-
} else if (term_is_boxed(t)) {
707-
TRACE("Found boxed (%p)\n", (void *) t);
708-
*ptr = memory_shallow_copy_term(old_fragment, t, &new_heap, move);
709-
ptr++;
710-
711-
} else {
712-
fprintf(stderr, "bug: found unknown term type: 0x%" TERM_X_FMT "\n", t);
713-
AVM_ABORT();
686+
case TERM_PRIMARY_LIST:
687+
TRACE("Found nonempty list (%p)\n", (void *) t);
688+
*ptr = memory_shallow_copy_term(old_fragment, t, &new_heap, move);
689+
ptr++;
690+
break;
691+
case TERM_PRIMARY_BOXED:
692+
TRACE("Found boxed (%p)\n", (void *) t);
693+
*ptr = memory_shallow_copy_term(old_fragment, t, &new_heap, move);
694+
ptr++;
695+
break;
696+
default:
697+
UNREACHABLE();
714698
}
715699
}
716700

@@ -835,90 +819,75 @@ HOT_FUNC static inline bool memory_heap_fragment_contains_pointer(HeapFragment *
835819

836820
HOT_FUNC static term memory_shallow_copy_term(HeapFragment *old_fragment, term t, term **new_heap, bool move)
837821
{
838-
if (term_is_atom(t)) {
839-
return t;
840-
841-
} else if (term_is_integer(t)) {
842-
return t;
843-
844-
} else if (term_is_nil(t)) {
845-
return t;
846-
847-
} else if (term_is_local_pid(t)) {
848-
return t;
849-
850-
} else if (term_is_local_port(t)) {
851-
return t;
852-
853-
} else if (term_is_cp(t)) {
854-
// CP is valid only on stack
855-
return t;
856-
857-
} else if (term_is_catch_label(t)) {
858-
// catch label is valid only on stack
859-
return t;
860-
861-
} else if (term_is_boxed(t)) {
862-
term *boxed_value = term_to_term_ptr(t);
863-
// Do not GC terms from messages until the message is destroyed
864-
if (old_fragment != NULL && !memory_heap_fragment_contains_pointer(old_fragment, boxed_value)) {
822+
switch (t & TERM_PRIMARY_MASK) {
823+
case TERM_PRIMARY_IMMED:
865824
return t;
866-
}
867825

868-
if (memory_is_moved_marker(boxed_value)) {
869-
return memory_dereference_moved_marker(boxed_value);
870-
}
826+
case TERM_PRIMARY_CP:
827+
// CP is valid only on stack
828+
// catch label is valid only on stack
829+
return t;
871830

872-
int boxed_size = term_boxed_size(t) + 1;
831+
case TERM_PRIMARY_BOXED: {
832+
term *boxed_value = term_to_term_ptr(t);
833+
// Do not GC terms from messages until the message is destroyed
834+
if (old_fragment != NULL && !memory_heap_fragment_contains_pointer(old_fragment, boxed_value)) {
835+
return t;
836+
}
873837

874-
// It must be an empty tuple, so we are not going to use moved markers.
875-
// Empty tuples memory is too small to store moved markers.
876-
// However it is also required to avoid boxed terms duplication.
877-
// So instead all empty tuples will reference the same boxed term.
878-
if (boxed_size == 1) {
879-
return ((term) &empty_tuple) | TERM_PRIMARY_BOXED;
880-
}
838+
if (memory_is_moved_marker(boxed_value)) {
839+
return memory_dereference_moved_marker(boxed_value);
840+
}
881841

882-
term *dest = *new_heap;
883-
for (int i = 0; i < boxed_size; i++) {
884-
dest[i] = boxed_value[i];
885-
}
886-
*new_heap += boxed_size;
842+
int boxed_size = term_boxed_size(t) + 1;
887843

888-
term new_term = ((term) dest) | TERM_PRIMARY_BOXED;
844+
// It must be an empty tuple, so we are not going to use moved markers.
845+
// Empty tuples memory is too small to store moved markers.
846+
// However it is also required to avoid boxed terms duplication.
847+
// So instead all empty tuples will reference the same boxed term.
848+
if (boxed_size == 1) {
849+
return ((term) &empty_tuple) | TERM_PRIMARY_BOXED;
850+
}
889851

890-
if (move) {
891-
memory_replace_with_moved_marker(boxed_value, new_term);
892-
}
852+
term *dest = *new_heap;
853+
for (int i = 0; i < boxed_size; i++) {
854+
dest[i] = boxed_value[i];
855+
}
856+
*new_heap += boxed_size;
893857

894-
return new_term;
858+
term new_term = ((term) dest) | TERM_PRIMARY_BOXED;
895859

896-
} else if (term_is_nonempty_list(t)) {
897-
term *list_ptr = term_get_list_ptr(t);
898-
if (old_fragment != NULL && !memory_heap_fragment_contains_pointer(old_fragment, list_ptr)) {
899-
return t;
900-
}
860+
if (move) {
861+
memory_replace_with_moved_marker(boxed_value, new_term);
862+
}
901863

902-
if (memory_is_moved_marker(list_ptr)) {
903-
return memory_dereference_moved_marker(list_ptr);
864+
return new_term;
904865
}
866+
case TERM_PRIMARY_LIST: {
867+
term *list_ptr = term_get_list_ptr(t);
868+
if (old_fragment != NULL && !memory_heap_fragment_contains_pointer(old_fragment, list_ptr)) {
869+
return t;
870+
}
905871

906-
term *dest = *new_heap;
907-
dest[0] = list_ptr[0];
908-
dest[1] = list_ptr[1];
909-
*new_heap += 2;
872+
if (memory_is_moved_marker(list_ptr)) {
873+
return memory_dereference_moved_marker(list_ptr);
874+
}
910875

911-
term new_term = ((term) dest) | 0x1;
876+
term *dest = *new_heap;
877+
dest[0] = list_ptr[0];
878+
dest[1] = list_ptr[1];
879+
*new_heap += 2;
912880

913-
if (move) {
914-
memory_replace_with_moved_marker(list_ptr, new_term);
915-
}
881+
term new_term = ((term) dest) | 0x1;
916882

917-
return new_term;
883+
if (move) {
884+
memory_replace_with_moved_marker(list_ptr, new_term);
885+
}
918886

919-
} else {
920-
fprintf(stderr, "Unexpected term. Term is: %" TERM_X_FMT "\n", t);
921-
AVM_ABORT();
887+
return new_term;
888+
}
889+
default:
890+
UNREACHABLE();
922891
}
923892
}
924893

src/libAtomVM/term.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
#define TERM_PRIMARY_CP 0x0
5353
#define TERM_PRIMARY_LIST 0x1
5454
#define TERM_PRIMARY_BOXED 0x2
55-
// #define TERM_PRIMARY_IMMED 0x3
55+
#define TERM_PRIMARY_IMMED 0x3
5656

5757
#define TERM_BOXED_VALUE_TAG _Pragma ("TERM_BOXED_VALUE_TAG is deprecated, use TERM_PRIMARY_BOXED instead") TERM_PRIMARY_BOXED
5858

0 commit comments

Comments
 (0)