Skip to content

Commit d103ac1

Browse files
committed
Handle truth values; speed up smallint checks
1 parent 36e2faf commit d103ac1

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

py/binary.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,16 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
308308
bool signed_type = is_signed(val_type);
309309
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
310310
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
311+
// It's a longint.
311312
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
312313
mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
313314
return;
314315
} else
315316
#endif
316317
{
317318
val = mp_obj_get_int(val_in);
318-
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
319+
// Small int checking is separate, to be fast.
320+
mp_small_int_buffer_overflow_check(val, size, signed_type);
319321
// zero/sign extend if needed
320322
if (BYTES_PER_WORD < 8 && size > sizeof(val)) {
321323
int c = (is_signed(val_type) && (mp_int_t)val < 0) ? 0xff : 0x00;
@@ -353,14 +355,16 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
353355

354356
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
355357
if (MP_OBJ_IS_TYPE(val_in, &mp_type_int)) {
358+
// It's a long int.
356359
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
357360
mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
358361
size, (uint8_t*)p + index * size);
359362
return;
360363
}
361364
#endif
362365
mp_int_t val = mp_obj_get_int(val_in);
363-
mp_obj_int_buffer_overflow_check(val_in, size, signed_type);
366+
// Small int checking is separate, to be fast.
367+
mp_small_int_buffer_overflow_check(val, size, signed_type);
364368
mp_binary_set_val_array_from_int(typecode, p, index, val);
365369
}
366370
}

py/objint.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
300300
return b;
301301
}
302302

303+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
304+
303305
void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed)
304306
{
305307
if (is_signed) {
@@ -329,7 +331,43 @@ void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_s
329331
}
330332
}
331333

332-
mp_raise_OverflowError_varg(translate("value would overflow a %d byte buffer"), nbytes);
334+
mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes);
335+
}
336+
337+
#endif // MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
338+
339+
void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed) {
340+
// Fast path for zero.
341+
if (val == 0) return;
342+
if (!is_signed) {
343+
if (val >= 0) {
344+
// Using signed constants here, not UINT8_MAX, etc. to avoid any unintended conversions.
345+
if (val <= 0xff) return; // Small values fit in any number of nbytes.
346+
if (nbytes == 2 && val <= 0xffff) return;
347+
#if !defined(__LP64__)
348+
// 32-bit ints and pointers
349+
if (nbytes >= 4) return; // Any mp_int_t will fit.
350+
#else
351+
// 64-bit ints and pointers
352+
if (nbytes == 4 && val <= 0xffffffff) return;
353+
if (nbytes >= 8) return; // Any mp_int_t will fit.
354+
#endif
355+
} // Negative, fall through to failure.
356+
} else {
357+
// signed
358+
if (val >= INT8_MIN && val <= INT8_MAX) return; // Small values fit in any number of nbytes.
359+
if (nbytes == 2 && val >= INT16_MIN && val <= INT16_MAX) return;
360+
#if !defined(__LP64__)
361+
// 32-bit ints and pointers
362+
if (nbytes >= 4) return; // Any mp_int_t will fit.
363+
#else
364+
// 64-bit ints and pointers
365+
if (nbytes == 4 && val >= INT32_MIN && val <= INT32_MAX) return;
366+
if (nbytes >= 8) return; // Any mp_int_t will fit.
367+
#endif
368+
} // Fall through to failure.
369+
370+
mp_raise_OverflowError_varg(translate("value must fit in %d byte(s)"), nbytes);
333371
}
334372

335373
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
@@ -467,15 +505,16 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *args) {
467505
byte *data = (byte*)vstr.buf;
468506
memset(data, 0, len);
469507

470-
mp_obj_int_buffer_overflow_check(args[0], len, false);
471-
472508
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
473509
if (!MP_OBJ_IS_SMALL_INT(args[0])) {
510+
mp_obj_int_buffer_overflow_check(args[0], len, false);
474511
mp_obj_int_to_bytes_impl(args[0], big_endian, len, data);
475512
} else
476513
#endif
477514
{
478515
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(args[0]);
516+
// Small int checking is separate, to be fast.
517+
mp_small_int_buffer_overflow_check(val, len, false);
479518
size_t l = MIN((size_t)len, sizeof(val));
480519
mp_binary_set_int(l, big_endian, data + (big_endian ? (len - l) : 0), val);
481520
}

py/objint.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
5353
int base, const char *prefix, char base_char, char comma);
5454
char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
5555
int base, const char *prefix, char base_char, char comma);
56+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
5657
void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed);
58+
#endif
59+
60+
void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed);
61+
5762
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
5863
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);
5964
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);

0 commit comments

Comments
 (0)