@ -38,6 +38,15 @@
# include "py/gc.h"
# include "py/mperrno.h"
// Extract the MP_MAX_UNCOMPRESSED_TEXT_LEN macro from "genhdr/compressed.data.h"
# if MICROPY_ROM_TEXT_COMPRESSION
# define MP_MATCH_COMPRESSED(...) // Ignore
# define MP_COMPRESSED_DATA(...) // Ignore
# include "genhdr/compressed.data.h"
# undef MP_MATCH_COMPRESSED
# undef MP_COMPRESSED_DATA
# endif
// Number of items per traceback entry (file, line, block)
# define TRACEBACK_ENTRY_LEN (3)
@ -57,6 +66,7 @@
# define EMG_BUF_TUPLE_OFFSET (EMG_BUF_TRACEBACK_OFFSET + EMG_BUF_TRACEBACK_SIZE)
# define EMG_BUF_TUPLE_SIZE(n_args) (sizeof(mp_obj_tuple_t) + n_args * sizeof(mp_obj_t))
# define EMG_BUF_STR_OFFSET (EMG_BUF_TUPLE_OFFSET + EMG_BUF_TUPLE_SIZE(1))
# define EMG_BUF_STR_BUF_OFFSET (EMG_BUF_STR_OFFSET + sizeof(mp_obj_str_t))
# if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
# define mp_emergency_exception_buf_size MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE
@ -100,6 +110,40 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
# endif
# endif // MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
STATIC void decompress_error_text_maybe ( mp_obj_exception_t * o ) {
# if MICROPY_ROM_TEXT_COMPRESSION
if ( o - > args - > len = = 1 & & mp_obj_is_type ( o - > args - > items [ 0 ] , & mp_type_str ) ) {
mp_obj_str_t * o_str = MP_OBJ_TO_PTR ( o - > args - > items [ 0 ] ) ;
if ( MP_IS_COMPRESSED_ROM_STRING ( o_str - > data ) ) {
byte * buf = m_new_maybe ( byte , MP_MAX_UNCOMPRESSED_TEXT_LEN + 1 ) ;
if ( ! buf ) {
# if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
// Try and use the emergency exception buf if enough space is available.
buf = ( byte * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + EMG_BUF_STR_BUF_OFFSET ) ;
size_t avail = ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + mp_emergency_exception_buf_size - buf ;
if ( avail < MP_MAX_UNCOMPRESSED_TEXT_LEN + 1 ) {
// No way to decompress, fallback to no message text.
o - > args = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
return ;
}
# else
o - > args = ( mp_obj_tuple_t * ) & mp_const_empty_tuple_obj ;
return ;
# endif
}
mp_decompress_rom_string ( buf , ( mp_rom_error_text_t ) o_str - > data ) ;
o_str - > data = buf ;
o_str - > len = strlen ( ( const char * ) buf ) ;
o_str - > hash = 0 ;
}
// Lazily compute the string hash.
if ( o_str - > hash = = 0 ) {
o_str - > hash = qstr_compute_hash ( o_str - > data , o_str - > len ) ;
}
}
# endif
}
void mp_obj_exception_print ( const mp_print_t * print , mp_obj_t o_in , mp_print_kind_t kind ) {
mp_obj_exception_t * o = MP_OBJ_TO_PTR ( o_in ) ;
mp_print_kind_t k = kind & ~ PRINT_EXC_SUBCLASS ;
@ -112,6 +156,8 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
mp_print_str ( print , " : " ) ;
}
decompress_error_text_maybe ( o ) ;
if ( k = = PRINT_STR | | k = = PRINT_EXC ) {
if ( o - > args = = NULL | | o - > args - > len = = 0 ) {
mp_print_str ( print , " " ) ;
@ -131,6 +177,7 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
return ;
}
}
mp_obj_tuple_print ( print , MP_OBJ_FROM_PTR ( o - > args ) , kind ) ;
}
@ -189,6 +236,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
if ( self - > args - > len = = 0 ) {
return mp_const_none ;
} else {
decompress_error_text_maybe ( self ) ;
return self - > args - > items [ 0 ] ;
}
}
@ -210,6 +258,7 @@ void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return ;
}
if ( attr = = MP_QSTR_args ) {
decompress_error_text_maybe ( self ) ;
dest [ 0 ] = MP_OBJ_FROM_PTR ( self - > args ) ;
} else if ( self - > base . type = = & mp_type_StopIteration & & attr = = MP_QSTR_value ) {
dest [ 0 ] = mp_obj_exception_get_value ( self_in ) ;
@ -323,7 +372,7 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args,
return mp_obj_exception_make_new ( exc_type , n_args , 0 , args ) ;
}
mp_obj_t mp_obj_new_exception_msg ( const mp_obj_type_t * exc_type , const char * msg ) {
mp_obj_t mp_obj_new_exception_msg ( const mp_obj_type_t * exc_type , mp_rom_error_text_t msg ) {
// Check that the given type is an exception type
assert ( exc_type - > make_new = = mp_obj_exception_make_new ) ;
@ -348,9 +397,13 @@ mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg
// Create the string object and call mp_obj_exception_make_new to create the exception
o_str - > base . type = & mp_type_str ;
o_str - > len = strlen ( msg ) ;
o_str - > len = strlen ( ( const char * ) msg ) ;
o_str - > data = ( const byte * ) msg ;
# if MICROPY_ROM_TEXT_COMPRESSION
o_str - > hash = 0 ; // will be computed only if string object is accessed
# else
o_str - > hash = qstr_compute_hash ( o_str - > data , o_str - > len ) ;
# endif
mp_obj_t arg = MP_OBJ_FROM_PTR ( o_str ) ;
return mp_obj_exception_make_new ( exc_type , 1 , 0 , & arg ) ;
}
@ -388,7 +441,7 @@ STATIC void exc_add_strn(void *data, const char *str, size_t len) {
pr - > len + = len ;
}
mp_obj_t mp_obj_new_exception_msg_varg ( const mp_obj_type_t * exc_type , const char * fmt , . . . ) {
mp_obj_t mp_obj_new_exception_msg_varg ( const mp_obj_type_t * exc_type , mp_rom_error_text_t fmt , . . . ) {
va_list args ;
va_start ( args , fmt ) ;
mp_obj_t exc = mp_obj_new_exception_msg_vlist ( exc_type , fmt , args ) ;
@ -396,7 +449,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char
return exc ;
}
mp_obj_t mp_obj_new_exception_msg_vlist ( const mp_obj_type_t * exc_type , const char * fmt , va_list args ) {
mp_obj_t mp_obj_new_exception_msg_vlist ( const mp_obj_type_t * exc_type , mp_rom_error_text_t fmt , va_list args ) {
assert ( fmt ! = NULL ) ;
// Check that the given type is an exception type
@ -404,7 +457,7 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const cha
// Try to allocate memory for the message
mp_obj_str_t * o_str = m_new_obj_maybe ( mp_obj_str_t ) ;
size_t o_str_alloc = strlen ( fmt ) + 1 ;
size_t o_str_alloc = strlen ( ( const char * ) fmt ) + 1 ;
byte * o_str_buf = m_new_maybe ( byte , o_str_alloc ) ;
bool used_emg_buf = false ;
@ -415,29 +468,39 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const cha
if ( ( o_str = = NULL | | o_str_buf = = NULL )
& & mp_emergency_exception_buf_size > = EMG_BUF_STR_OFFSET + sizeof ( mp_obj_str_t ) + 16 ) {
used_emg_buf = true ;
o_str = ( mp_obj_str_t * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf )
+ EMG_BUF_STR_OFFSET ) ;
o_str_buf = ( byte * ) & o_str [ 1 ] ;
o_str_alloc = ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf )
+ mp_emergency_exception_buf_size - o_str_buf ;
o_str = ( mp_obj_str_t * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + EMG_BUF_STR_OFFSET ) ;
o_str_buf = ( byte * ) ( ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + EMG_BUF_STR_BUF_OFFSET ) ;
o_str_alloc = ( uint8_t * ) MP_STATE_VM ( mp_emergency_exception_buf ) + mp_emergency_exception_buf_size - o_str_buf ;
}
# endif
if ( o_str = = NULL ) {
// No memory for the string object so create the exception with no args
// No memory for the string object so create the exception with no args.
// The exception will only have a type and no message (compression is irrelevant).
return mp_obj_exception_make_new ( exc_type , 0 , 0 , NULL ) ;
}
if ( o_str_buf = = NULL ) {
// No memory for the string buffer: assume that the fmt string is in ROM
// and use that data as the data of the string
// and use that data as the data of the string.
// The string will point directly to the compressed data -- will need to be decompressed
// prior to display (this case is identical to mp_obj_new_exception_msg above).
o_str - > len = o_str_alloc - 1 ; // will be equal to strlen(fmt)
o_str - > data = ( const byte * ) fmt ;
} else {
// We have some memory to format the string
// We have some memory to format the string.
// TODO: Optimise this to format-while-decompressing (and not require the temp stack space).
struct _exc_printer_t exc_pr = { ! used_emg_buf , o_str_alloc , 0 , o_str_buf } ;
mp_print_t print = { & exc_pr , exc_add_strn } ;
mp_vprintf ( & print , fmt , args ) ;
const char * fmt2 = ( const char * ) fmt ;
# if MICROPY_ROM_TEXT_COMPRESSION
byte decompressed [ MP_MAX_UNCOMPRESSED_TEXT_LEN ] ;
if ( MP_IS_COMPRESSED_ROM_STRING ( fmt ) ) {
mp_decompress_rom_string ( decompressed , fmt ) ;
fmt2 = ( const char * ) decompressed ;
}
# endif
mp_vprintf ( & print , fmt2 , args ) ;
exc_pr . buf [ exc_pr . len ] = ' \0 ' ;
o_str - > len = exc_pr . len ;
o_str - > data = exc_pr . buf ;
@ -445,7 +508,11 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const cha
// Create the string object and call mp_obj_exception_make_new to create the exception
o_str - > base . type = & mp_type_str ;
# if MICROPY_ROM_TEXT_COMPRESSION
o_str - > hash = 0 ; // will be computed only if string object is accessed
# else
o_str - > hash = qstr_compute_hash ( o_str - > data , o_str - > len ) ;
# endif
mp_obj_t arg = MP_OBJ_FROM_PTR ( o_str ) ;
return mp_obj_exception_make_new ( exc_type , 1 , 0 , & arg ) ;
}