3131#include "bitstring.h"
3232#include "defaultatoms.h"
3333#include "memory.h"
34+ #include "module.h"
3435#include "term.h"
3536#include "unicode.h"
3637#include "utils.h"
4950#define LIST_EXT 108
5051#define BINARY_EXT 109
5152#define SMALL_BIG_EXT 110
53+ #define NEW_FUN_EXT 112
5254#define EXPORT_EXT 113
5355#define MAP_EXT 116
5456#define ATOM_UTF8_EXT 118
@@ -362,7 +364,7 @@ static int serialize_term(uint8_t *buf, term t, GlobalContext *glb)
362364 k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , value , glb );
363365 }
364366 return k ;
365- } else if (term_is_function (t )) {
367+ } else if (term_is_external_fun (t )) {
366368 if (!IS_NULL_PTR (buf )) {
367369 buf [0 ] = EXPORT_EXT ;
368370 }
@@ -373,6 +375,50 @@ static int serialize_term(uint8_t *buf, term t, GlobalContext *glb)
373375 k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , mfa , glb );
374376 }
375377 return k ;
378+ } else if (term_is_function (t )) {
379+ const term * boxed_value = term_to_const_term_ptr (t );
380+ size_t num_free = (((uintptr_t ) boxed_value [0 ]) >> 6 ) - 2 ;
381+ // TODO: old_uniq is marked deprecated in OTP source likely to be removed in OTP29
382+ term module , old_uniq , old_index ;
383+ uint32_t arity ;
384+ uint32_t index = term_to_int32 (boxed_value [2 ]);
385+ size_t free_index ;
386+ if (term_is_atom (boxed_value [1 ])) {
387+ module = boxed_value [1 ];
388+ arity = term_to_int32 (boxed_value [3 ]);
389+ old_index = boxed_value [4 ];
390+ old_uniq = boxed_value [5 ];
391+ free_index = 6 ;
392+ num_free -= 3 ;
393+ } else {
394+ Module * mod = (Module * ) boxed_value [1 ];
395+ module = module_get_name (mod );
396+ uint32_t f_old_index , f_old_uniq ;
397+ module_get_fun_arity_old_index_uniq (mod , index , & arity , & f_old_index , & f_old_uniq );
398+ old_uniq = term_from_int (f_old_uniq );
399+ old_index = term_from_int (f_old_index );
400+ free_index = 3 ;
401+ }
402+
403+ if (!IS_NULL_PTR (buf )) {
404+ buf [0 ] = NEW_FUN_EXT ;
405+ buf [5 ] = arity - num_free ;
406+ bzero (buf + 6 , 16 );
407+ WRITE_32_UNALIGNED (buf + 22 , index );
408+ WRITE_32_UNALIGNED (buf + 26 , num_free );
409+ }
410+ size_t k = 1 + 4 + 1 + 16 + 4 + 4 ;
411+ k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , module , glb );
412+ k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , old_index , glb );
413+ k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , old_uniq , glb );
414+ k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , term_from_local_process_id (0 ), glb );
415+ for (size_t i = 0 ; i < num_free ; i ++ ) {
416+ k += serialize_term (IS_NULL_PTR (buf ) ? NULL : buf + k , boxed_value [free_index + i ], glb );
417+ }
418+ if (!IS_NULL_PTR (buf )) {
419+ WRITE_32_UNALIGNED (buf + 1 , k - 1 );
420+ }
421+ return k ;
376422 } else if (term_is_local_pid (t )) {
377423 if (!IS_NULL_PTR (buf )) {
378424 buf [0 ] = NEW_PID_EXT ;
@@ -814,6 +860,60 @@ static term parse_external_terms(const uint8_t *external_term_buf, size_t *eterm
814860 }
815861 }
816862
863+ case NEW_FUN_EXT : {
864+ uint32_t len = READ_32_UNALIGNED (external_term_buf + 1 );
865+ uint8_t arity = external_term_buf [5 ];
866+ uint32_t index = READ_32_UNALIGNED (external_term_buf + 22 );
867+ uint32_t num_free = READ_32_UNALIGNED (external_term_buf + 26 );
868+ size_t term_size ;
869+ size_t offset = 30 ;
870+ term module = parse_external_terms (external_term_buf + offset , & term_size , copy , heap , glb );
871+ offset += term_size ;
872+ term old_index = parse_external_terms (external_term_buf + offset , & term_size , copy , heap , glb );
873+ offset += term_size ;
874+ // TODO: old_uniq is marked deprecated in OTP source likely to be removed in OTP29
875+ term old_uniq = parse_external_terms (external_term_buf + offset , & term_size , copy , heap , glb );
876+ offset += term_size ;
877+ // skip pid
878+ if (UNLIKELY (calculate_heap_usage (external_term_buf + offset , len - offset + 1 , & term_size , copy ) == INVALID_TERM_SIZE )) {
879+ return term_invalid_term ();
880+ }
881+ offset += term_size ;
882+ Module * mod = globalcontext_get_module (glb , term_to_atom_index (module ));
883+ if (!IS_NULL_PTR (mod )) {
884+ uint32_t f_arity , f_old_index , f_old_uniq ;
885+ module_get_fun_arity_old_index_uniq (mod , index , & f_arity , & f_old_index , & f_old_uniq );
886+ if (UNLIKELY (f_arity != (arity + num_free ) || f_old_index != (uint32_t ) term_to_int32 (old_index ) || f_old_uniq != (uint32_t ) term_to_int32 (old_uniq ))) {
887+ mod = NULL ;
888+ }
889+ }
890+ size_t size = BOXED_FUN_SIZE + num_free ;
891+ if (IS_NULL_PTR (mod )) {
892+ size += 3 ;
893+ }
894+ term * boxed_func = memory_heap_alloc (heap , size );
895+ boxed_func [0 ] = ((size - 1 ) << 6 ) | TERM_BOXED_FUN ;
896+ size_t free_index ;
897+ if (IS_NULL_PTR (mod )) {
898+ boxed_func [1 ] = module ;
899+ boxed_func [3 ] = term_from_int (arity );
900+ boxed_func [4 ] = old_index ;
901+ boxed_func [5 ] = old_uniq ;
902+ free_index = 6 ;
903+ } else {
904+ boxed_func [1 ] = (term ) mod ;
905+ free_index = 3 ;
906+ }
907+
908+ boxed_func [2 ] = term_from_int (index );
909+ for (uint32_t i = 0 ; i < num_free ; i ++ ) {
910+ boxed_func [i + free_index ] = parse_external_terms (external_term_buf + offset , & term_size , copy , heap , glb );
911+ offset += term_size ;
912+ }
913+ * eterm_size = len + 1 ;
914+ return ((term ) boxed_func ) | TERM_PRIMARY_BOXED ;
915+ }
916+
817917 default :
818918 return term_invalid_term ();
819919 }
@@ -1167,6 +1267,47 @@ static int calculate_heap_usage(const uint8_t *external_term_buf, size_t remaini
11671267 return heap_size + u ;
11681268 }
11691269
1270+ case NEW_FUN_EXT : {
1271+ if (UNLIKELY (remaining < 30 )) {
1272+ return INVALID_TERM_SIZE ;
1273+ }
1274+ uint32_t len = READ_32_UNALIGNED (external_term_buf + 1 );
1275+ remaining -= 1 ;
1276+ if (UNLIKELY (remaining < len )) {
1277+ return INVALID_TERM_SIZE ;
1278+ }
1279+ uint32_t num_free = READ_32_UNALIGNED (external_term_buf + 26 );
1280+ // If module doesn't match or exist, we'll need 3 more for arity, old_index and old_uniq
1281+ size_t heap_size = BOXED_FUN_SIZE + num_free + 3 ;
1282+ int u ;
1283+ if (num_free > 0 ) {
1284+ remaining -= 29 ;
1285+ size_t offset = 30 ;
1286+ size_t term_size ;
1287+ // skip module atom, old index, old uniq, pid
1288+ for (int i = 0 ; i < 4 ; i ++ ) {
1289+ u = calculate_heap_usage (external_term_buf + offset , remaining , & term_size , copy );
1290+ if (UNLIKELY (u == INVALID_TERM_SIZE )) {
1291+ return INVALID_TERM_SIZE ;
1292+ }
1293+ remaining -= term_size ;
1294+ offset += term_size ;
1295+ }
1296+ // add free values
1297+ for (size_t i = 0 ; i < num_free ; i ++ ) {
1298+ u = calculate_heap_usage (external_term_buf + offset , remaining , & term_size , copy );
1299+ if (UNLIKELY (u == INVALID_TERM_SIZE )) {
1300+ return INVALID_TERM_SIZE ;
1301+ }
1302+ heap_size += u ;
1303+ remaining -= term_size ;
1304+ offset += term_size ;
1305+ }
1306+ }
1307+ * eterm_size = 1 + len ;
1308+ return heap_size ;
1309+ }
1310+
11701311 default :
11711312 return INVALID_TERM_SIZE ;
11721313 }
0 commit comments