Commit 88d7bba9 authored by Damien George's avatar Damien George
Browse files

py: Make it so that printing a small int does not allocate heap memory.

With the implementation of proper string formatting, code to print a
small int was delegated to mpz_as_str_inpl (after first converting the
small int to an mpz using stack memory).  But mpz_as_str_inpl allocates
heap memory to do the conversion, so small ints needed heap memory just
to be printed.

This fix has a separate function to print small ints, which does not
allocate heap, and allocates less stack.

String formatting, printf and pfenv are now large beasts, with some
semi-duplicated code.
parent 803b9263
......@@ -70,15 +70,13 @@ void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env,
}
}
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE || MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
typedef mp_longint_impl_t fmt_int_t;
typedef mp_longint_impl_t fmt_int_t;
#else
typedef mp_small_int_t fmt_int_t;
typedef mp_small_int_t fmt_int_t;
#endif
static const uint log_base2_floor[] = {
STATIC const uint log_base2_floor[] = {
0,
0, 1, 1, 2,
2, 2, 2, 3,
......@@ -90,7 +88,7 @@ static const uint log_base2_floor[] = {
4, 4, 4, 5
};
uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
if (base < 2 || base > 32) {
return 0;
}
......@@ -110,22 +108,29 @@ uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
// formatted size will be in *fmt_size.
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
if (!MP_OBJ_IS_INT(self_in)) {
buf[0] = '\0';
*fmt_size = 0;
return *buf;
}
fmt_int_t num;
if (MP_OBJ_IS_SMALL_INT(self_in)) {
// A small int; get the integer value to format.
num = mp_obj_get_int(self_in);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
// Not a small int.
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
mp_obj_int_t *self = self_in;
if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
// mp_obj_get_int truncates to machine_int_t
mp_obj_int_t *self = self_in;
// Get the value to format; mp_obj_get_int truncates to machine_int_t.
num = self->val;
} else
#else
// Delegate to the implementation for the long int.
return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
#endif
{
num = mp_obj_get_int(self_in);
#endif
} else {
// Not an int.
buf[0] = '\0';
*fmt_size = 0;
return *buf;
}
char sign = '\0';
if (num < 0) {
num = -num;
......@@ -180,12 +185,11 @@ char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t se
return b;
}
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
bool mp_obj_int_is_positive(mp_obj_t self_in) {
return mp_obj_get_int(self_in) >= 0;
}
#endif // LONGLONG or NONE
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
......
......@@ -10,6 +10,8 @@ typedef struct _mp_obj_int_t {
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
bool mp_obj_int_is_positive(mp_obj_t self_in);
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
......
......@@ -22,6 +22,14 @@
#define SUFFIX ""
#endif
bool mp_obj_int_is_positive(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
}
mp_obj_int_t *self = self_in;
return self->val >= 0;
}
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
mp_obj_int_t *o = o_in;
switch (op) {
......
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "nlr.h"
#include "misc.h"
......@@ -29,30 +30,21 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
//
// The resulting formatted string will be returned from this function and the
// formatted size will be in *fmt_size.
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
mpz_t small_mpz;
mpz_t *mpz;
mpz_dig_t small_dig[(sizeof(mp_small_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE];
if (MP_OBJ_IS_SMALL_INT(self_in)) {
mpz_init_fixed_from_int(&small_mpz, small_dig,
sizeof(small_dig) / sizeof(small_dig[0]),
MP_OBJ_SMALL_INT_VALUE(self_in));
mpz = &small_mpz;
} else {
mp_obj_int_t *self = self_in;
mpz = &self->mpz;
}
//
// This particular routine should only be called for the mpz representation of the int.
char *mp_obj_int_formatted_impl(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
mp_obj_int_t *self = self_in;
uint needed_size = mpz_as_str_size_formatted(mpz, base, prefix, comma);
uint needed_size = mpz_as_str_size_formatted(&self->mpz, base, prefix, comma);
if (needed_size > *buf_size) {
*buf = m_new(char, needed_size);
*buf_size = needed_size;
}
char *str = *buf;
*fmt_size = mpz_as_str_inpl(mpz, base, prefix, base_char, comma, str);
*fmt_size = mpz_as_str_inpl(&self->mpz, base, prefix, base_char, comma, str);
return str;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment