@@ -526,7 +526,7 @@ void mp_raw_code_load_file(qstr filename, mp_compiled_module_t *context) {
526
526
527
527
#endif // MICROPY_PERSISTENT_CODE_LOAD
528
528
529
- #if MICROPY_PERSISTENT_CODE_SAVE
529
+ #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_PERSISTENT_CODE_SAVE_FUN
530
530
531
531
#include "py/objstr.h"
532
532
@@ -624,6 +624,10 @@ static void save_obj(mp_print_t *print, mp_obj_t o) {
624
624
}
625
625
}
626
626
627
+ #endif // MICROPY_PERSISTENT_CODE_SAVE || MICROPY_PERSISTENT_CODE_SAVE_FUN
628
+
629
+ #if MICROPY_PERSISTENT_CODE_SAVE
630
+
627
631
static void save_raw_code (mp_print_t * print , const mp_raw_code_t * rc ) {
628
632
// Save function kind and data length
629
633
mp_print_uint (print , (rc -> fun_data_len << 3 ) | ((rc -> n_children != 0 ) << 2 ) | (rc -> kind - MP_CODE_BYTECODE ));
@@ -693,6 +697,8 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) {
693
697
save_raw_code (print , cm -> rc );
694
698
}
695
699
700
+ #endif // MICROPY_PERSISTENT_CODE_SAVE
701
+
696
702
#if MICROPY_PERSISTENT_CODE_SAVE_FILE
697
703
698
704
#include <unistd.h>
@@ -723,4 +729,184 @@ void mp_raw_code_save_file(mp_compiled_module_t *cm, qstr filename) {
723
729
724
730
#endif // MICROPY_PERSISTENT_CODE_SAVE_FILE
725
731
726
- #endif // MICROPY_PERSISTENT_CODE_SAVE
732
+ #if MICROPY_PERSISTENT_CODE_SAVE_FUN
733
+
734
+ #include "py/bc0.h"
735
+ #include "py/objfun.h"
736
+ #include "py/smallint.h"
737
+ #include "py/gc.h"
738
+
739
+ #define MP_BC_OPCODE_HAS_SIGNED_OFFSET (opcode ) (MP_BC_UNWIND_JUMP <= (opcode) && (opcode) <= MP_BC_POP_JUMP_IF_FALSE)
740
+
741
+ typedef struct _bit_vector_t {
742
+ size_t max_bit_set ;
743
+ size_t alloc ;
744
+ uintptr_t * bits ;
745
+ } bit_vector_t ;
746
+
747
+ static void bit_vector_init (bit_vector_t * self ) {
748
+ self -> max_bit_set = 0 ;
749
+ self -> alloc = 1 ;
750
+ self -> bits = m_new (uintptr_t , self -> alloc );
751
+ }
752
+
753
+ static void bit_vector_clear (bit_vector_t * self ) {
754
+ m_del (uintptr_t , self -> bits , self -> alloc );
755
+ }
756
+
757
+ static bool bit_vector_is_set (bit_vector_t * self , size_t index ) {
758
+ const size_t bits_size = sizeof (* self -> bits ) * MP_BITS_PER_BYTE ;
759
+ return index / bits_size < self -> alloc
760
+ && (self -> bits [index / bits_size ] & (1 << (index % bits_size ))) != 0 ;
761
+ }
762
+
763
+ static void bit_vector_set (bit_vector_t * self , size_t index ) {
764
+ const size_t bits_size = sizeof (* self -> bits ) * MP_BITS_PER_BYTE ;
765
+ self -> max_bit_set = MAX (self -> max_bit_set , index );
766
+ if (index / bits_size >= self -> alloc ) {
767
+ size_t new_alloc = self -> alloc * 2 ;
768
+ self -> bits = m_renew (uintptr_t , self -> bits , self -> alloc , new_alloc );
769
+ self -> alloc = new_alloc ;
770
+ }
771
+ self -> bits [index / bits_size ] |= 1 << (index % bits_size );
772
+ }
773
+
774
+ typedef struct _mp_opcode_t {
775
+ uint8_t opcode ;
776
+ uint8_t format ;
777
+ uint8_t size ;
778
+ mp_int_t arg ;
779
+ uint8_t extra_arg ;
780
+ } mp_opcode_t ;
781
+
782
+ static mp_opcode_t mp_opcode_decode (const uint8_t * ip ) {
783
+ const uint8_t * ip_start = ip ;
784
+ uint8_t opcode = * ip ++ ;
785
+ uint8_t opcode_format = MP_BC_FORMAT (opcode );
786
+ mp_uint_t arg = 0 ;
787
+ uint8_t extra_arg = 0 ;
788
+ if (opcode_format == MP_BC_FORMAT_QSTR || opcode_format == MP_BC_FORMAT_VAR_UINT ) {
789
+ arg = * ip & 0x7f ;
790
+ if (opcode == MP_BC_LOAD_CONST_SMALL_INT && (arg & 0x40 ) != 0 ) {
791
+ arg |= (mp_uint_t )(-1 ) << 7 ;
792
+ }
793
+ while ((* ip & 0x80 ) != 0 ) {
794
+ arg = (arg << 7 ) | (* ++ ip & 0x7f );
795
+ }
796
+ ++ ip ;
797
+ } else if (opcode_format == MP_BC_FORMAT_OFFSET ) {
798
+ if ((* ip & 0x80 ) == 0 ) {
799
+ arg = * ip ++ ;
800
+ if (MP_BC_OPCODE_HAS_SIGNED_OFFSET (opcode )) {
801
+ arg -= 0x40 ;
802
+ }
803
+ } else {
804
+ arg = (ip [0 ] & 0x7f ) | (ip [1 ] << 7 );
805
+ ip += 2 ;
806
+ if (MP_BC_OPCODE_HAS_SIGNED_OFFSET (opcode )) {
807
+ arg -= 0x4000 ;
808
+ }
809
+ }
810
+ }
811
+ if ((opcode & MP_BC_MASK_EXTRA_BYTE ) == 0 ) {
812
+ extra_arg = * ip ++ ;
813
+ }
814
+
815
+ mp_opcode_t op = { opcode , opcode_format , ip - ip_start , arg , extra_arg };
816
+ return op ;
817
+ }
818
+
819
+ mp_obj_t mp_raw_code_save_fun_to_bytes (const mp_module_constants_t * consts , const uint8_t * bytecode ) {
820
+ const uint8_t * fun_data = bytecode ;
821
+ const uint8_t * fun_data_top = fun_data + gc_nbytes (fun_data );
822
+
823
+ // Extract function information.
824
+ const byte * ip = fun_data ;
825
+ MP_BC_PRELUDE_SIG_DECODE (ip );
826
+ MP_BC_PRELUDE_SIZE_DECODE (ip );
827
+
828
+ // Track the qstrs used by the function.
829
+ bit_vector_t qstr_table_used ;
830
+ bit_vector_init (& qstr_table_used );
831
+
832
+ // Track the objects used by the function.
833
+ bit_vector_t obj_table_used ;
834
+ bit_vector_init (& obj_table_used );
835
+
836
+ const byte * ip_names = ip ;
837
+ mp_uint_t simple_name = mp_decode_uint (& ip_names );
838
+ bit_vector_set (& qstr_table_used , simple_name );
839
+ for (size_t i = 0 ; i < n_pos_args + n_kwonly_args ; ++ i ) {
840
+ mp_uint_t arg_name = mp_decode_uint (& ip_names );
841
+ bit_vector_set (& qstr_table_used , arg_name );
842
+ }
843
+
844
+ // Skip pass source code info and cell info.
845
+ // Then ip points to the start of the opcodes.
846
+ ip += n_info + n_cell ;
847
+
848
+ // Decode bytecode.
849
+ while (ip < fun_data_top ) {
850
+ mp_opcode_t op = mp_opcode_decode (ip );
851
+ if (op .opcode == MP_BC_BASE_RESERVED ) {
852
+ // End of opcodes.
853
+ fun_data_top = ip ;
854
+ } else if (op .opcode == MP_BC_LOAD_CONST_OBJ ) {
855
+ bit_vector_set (& obj_table_used , op .arg );
856
+ } else if (op .format == MP_BC_FORMAT_QSTR ) {
857
+ bit_vector_set (& qstr_table_used , op .arg );
858
+ }
859
+ ip += op .size ;
860
+ }
861
+
862
+ mp_uint_t fun_data_len = fun_data_top - fun_data ;
863
+
864
+ mp_print_t print ;
865
+ vstr_t vstr ;
866
+ vstr_init_print (& vstr , 64 , & print );
867
+
868
+ // Start with .mpy header.
869
+ const uint8_t header [4 ] = { 'M' , MPY_VERSION , 0 , MP_SMALL_INT_BITS };
870
+ mp_print_bytes (& print , header , sizeof (header ));
871
+
872
+ // Number of entries in constant table.
873
+ mp_print_uint (& print , qstr_table_used .max_bit_set + 1 );
874
+ mp_print_uint (& print , obj_table_used .max_bit_set + 1 );
875
+
876
+ // Save qstrs.
877
+ for (size_t i = 0 ; i <= qstr_table_used .max_bit_set ; ++ i ) {
878
+ if (bit_vector_is_set (& qstr_table_used , i )) {
879
+ save_qstr (& print , consts -> qstr_table [i ]);
880
+ } else {
881
+ save_qstr (& print , MP_QSTR_ );
882
+ }
883
+ }
884
+
885
+ // Save constant objects.
886
+ for (size_t i = 0 ; i <= obj_table_used .max_bit_set ; ++ i ) {
887
+ if (bit_vector_is_set (& obj_table_used , i )) {
888
+ save_obj (& print , consts -> obj_table [i ]);
889
+ } else {
890
+ save_obj (& print , mp_const_none );
891
+ }
892
+ }
893
+
894
+ bit_vector_clear (& qstr_table_used );
895
+ bit_vector_clear (& obj_table_used );
896
+
897
+ // Save function kind and data length.
898
+ mp_print_uint (& print , fun_data_len << 3 );
899
+
900
+ // Save function code.
901
+ mp_print_bytes (& print , fun_data , fun_data_len );
902
+
903
+ // Create and return bytes representing the .mpy data.
904
+ return mp_obj_new_bytes_from_vstr (& vstr );
905
+ }
906
+
907
+ #endif // MICROPY_PERSISTENT_CODE_SAVE_FUN
908
+
909
+ #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE
910
+ // An mp_obj_list_t that tracks relocated native code to prevent the GC from reclaiming them.
911
+ MP_REGISTER_ROOT_POINTER (mp_obj_t track_reloc_code_list );
912
+ #endif
0 commit comments