From 6276a4f6a5dbba84e87eaccc21495ffee5f64b51 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Thu, 26 Sep 2024 00:05:40 -0600 Subject: [PATCH] Various stack size reduction tweaks * Add option for skipping size checks when encoding submessages * Tweak inline/noinline for functions to reduce stack size. --- pb.h | 16 ++++++++++++++++ pb_encode.c | 22 ++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/pb.h b/pb.h index 8745ecc6a..e9fe8dba0 100644 --- a/pb.h +++ b/pb.h @@ -28,6 +28,9 @@ /* Disable support for error messages in order to save some code space. */ /* #define PB_NO_ERRMSG 1 */ +/* Disable checks to ensure sub-message encoded size is consistent when re-run. */ +/* #define PB_NO_ENCODE_SIZE_CHECK 1 */ + /* Disable support for custom streams (support only memory buffers). */ /* #define PB_BUFFER_ONLY 1 */ @@ -126,6 +129,19 @@ extern "C" { # define pb_packed #endif +// Define for explicitly not inlining a given function +#if defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define pb_noinline __attribute__((noinline)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +# define pb_noinline +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) +# define pb_noinline __declspec(noinline) +#else +# define pb_noinline +#endif + /* Detect endianness */ #ifndef PB_LITTLE_ENDIAN_8BIT #if ((defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \ diff --git a/pb_encode.c b/pb_encode.c index 7f5620125..635807244 100644 --- a/pb_encode.c +++ b/pb_encode.c @@ -26,7 +26,7 @@ static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *fie static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field); static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field); static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field); -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field); +static pb_noinline bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field); static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high); static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field); @@ -483,7 +483,7 @@ static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb /* Walk through all the registered extensions and give them a chance * to encode themselves. */ -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field) +static pb_noinline bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field) { const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; @@ -724,8 +724,6 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t * { /* First calculate the message size using a non-writing substream. */ pb_ostream_t substream = PB_OSTREAM_SIZING; - size_t size; - bool status; if (!pb_encode(&substream, fields, src_struct)) { @@ -735,17 +733,20 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t * return false; } - size = substream.bytes_written; - - if (!pb_encode_varint(stream, (pb_uint64_t)size)) + if (!pb_encode_varint(stream, (pb_uint64_t)substream.bytes_written)) return false; if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing */ + return pb_write(stream, NULL, substream.bytes_written); /* Just sizing */ - if (stream->bytes_written + size > stream->max_size) + if (stream->bytes_written + substream.bytes_written > stream->max_size) PB_RETURN_ERROR(stream, "stream full"); +#if PB_NO_ENCODE_SIZE_CHECK + return pb_encode(stream, fields, src_struct); +#else + bool status; + size_t size = substream.bytes_written; /* Use a substream to verify that a callback doesn't write more than * what it did the first time. */ substream.callback = stream->callback; @@ -766,8 +767,9 @@ bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t * if (substream.bytes_written != size) PB_RETURN_ERROR(stream, "submsg size changed"); - + return status; +#endif } /* Field encoders */