summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-04-08 23:30:46 +0100
committerDamien George <damien.p.george@gmail.com>2014-04-08 23:30:46 +0100
commit88d7bba961cb38c594d72b6be5847cb1106f91b2 (patch)
tree4d49fb9d1c61148dde6e3429ccb950449e3f3581 /py
parent803b9263ab1049d19d62d9a09e5f82084b7afa41 (diff)
downloadmicropython-88d7bba961cb38c594d72b6be5847cb1106f91b2.tar.gz
micropython-88d7bba961cb38c594d72b6be5847cb1106f91b2.zip
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.
Diffstat (limited to 'py')
-rw-r--r--py/objint.c44
-rw-r--r--py/objint.h2
-rw-r--r--py/objint_longlong.c8
-rw-r--r--py/objint_mpz.c26
4 files changed, 43 insertions, 37 deletions
diff --git a/py/objint.c b/py/objint.c
index 05269ce379..69954168de 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -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) {
diff --git a/py/objint.h b/py/objint.h
index 7ee476269c..5b21d55fe8 100644
--- a/py/objint.h
+++ b/py/objint.h
@@ -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);
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index 332f0bbb8a..24435415fb 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -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) {
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 6410ecc64d..583ce4cb78 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -1,6 +1,7 @@
#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;
}