Merge remote-tracking branch 'origin/main' into main

This commit is contained in:
Hosted Weblate 2021-06-23 19:15:26 +02:00
commit c0b28c4510
No known key found for this signature in database
GPG Key ID: A3FAAA06E6569B4C
140 changed files with 1653 additions and 602 deletions

View File

@ -1,3 +1,6 @@
# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
0f78c36c5aa458a954eed39a46942209107a553e
# tests/run-tests.py: Reformat with Black. # tests/run-tests.py: Reformat with Black.
2a38d7103672580882fb621a5b76e8d26805d593 2a38d7103672580882fb621a5b76e8d26805d593

View File

@ -182,10 +182,6 @@ Exceptions
.. exception:: OSError .. exception:: OSError
|see_cpython| :py:class:`cpython:OSError`. CircuitPython doesn't implement the ``errno``
attribute, instead use the standard way to access exception arguments:
``exc.args[0]``.
.. exception:: RuntimeError .. exception:: RuntimeError
.. exception:: ReloadException .. exception:: ReloadException

View File

@ -214,6 +214,14 @@ TCP stream connections
This is a coroutine. This is a coroutine.
.. method:: Stream.readinto(buf)
Read up to n bytes into *buf* with n being equal to the length of *buf*.
Return the number of bytes read into *buf*.
This is a coroutine, and a MicroPython extension.
.. method:: Stream.readline() .. method:: Stream.readline()
Read a line and return it. Read a line and return it.

View File

@ -247,7 +247,7 @@ Module contents
.. data:: VOID .. data:: VOID
``VOID`` is an alias for ``UINT8``, and is provided to conviniently define ``VOID`` is an alias for ``UINT8``, and is provided to conveniently define
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``. C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
.. data:: PTR .. data:: PTR

View File

@ -8,9 +8,11 @@
|see_cpython_module| :mod:`cpython:heapq`. |see_cpython_module| :mod:`cpython:heapq`.
This module implements the heap queue algorithm. This module implements the
`min heap queue algorithm <https://en.wikipedia.org/wiki/Heap_%28data_structure%29>`_.
A heap queue is simply a list that has its elements stored in a certain way. A heap queue is essentially a list that has its elements stored in such a way
that the first item of the list is always the smallest.
Functions Functions
--------- ---------
@ -21,8 +23,10 @@ Functions
.. function:: heappop(heap) .. function:: heappop(heap)
Pop the first item from the ``heap``, and return it. Raises IndexError if Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
heap is empty. ``heap`` is empty.
The returned item will be the smallest item in the ``heap``.
.. function:: heapify(x) .. function:: heapify(x)

View File

@ -89,11 +89,11 @@ Methods
``callee-owned tuples``. This function provides efficient, allocation-free ``callee-owned tuples``. This function provides efficient, allocation-free
way to poll on streams. way to poll on streams.
If *flags* is 1, one-shot behavior for events is employed: streams for If *flags* is 1, one-shot behaviour for events is employed: streams for
which events happened will have their event masks automatically reset which events happened will have their event masks automatically reset
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream (equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
won't be processed until new mask is set with `poll.modify()`. This won't be processed until new mask is set with `poll.modify()`. This
behavior is useful for asynchronous I/O schedulers. behaviour is useful for asynchronous I/O schedulers.
.. admonition:: Difference to CPython .. admonition:: Difference to CPython
:class: attention :class: attention

View File

@ -31,12 +31,19 @@
#if MICROPY_PY_UASYNCIO #if MICROPY_PY_UASYNCIO
#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
#define TASK_IS_DONE(task) ( \
(task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
|| (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
typedef struct _mp_obj_task_t { typedef struct _mp_obj_task_t {
mp_pairheap_t pairheap; mp_pairheap_t pairheap;
mp_obj_t coro; mp_obj_t coro;
mp_obj_t data; mp_obj_t data;
mp_obj_t waiting; mp_obj_t state;
mp_obj_t ph_key; mp_obj_t ph_key;
} mp_obj_task_t; } mp_obj_task_t;
@ -146,9 +153,6 @@ STATIC const mp_obj_type_t task_queue_type = {
/******************************************************************************/ /******************************************************************************/
// Task class // Task class
// For efficiency, the task object is stored to the coro entry when the task is done.
#define TASK_IS_DONE(task) ((task)->coro == MP_OBJ_FROM_PTR(task))
// This is the core uasyncio context with cur_task, _task_queue and CancelledError. // This is the core uasyncio context with cur_task, _task_queue and CancelledError.
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL; STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
@ -159,7 +163,7 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, const mp
mp_pairheap_init_node(task_lt, &self->pairheap); mp_pairheap_init_node(task_lt, &self->pairheap);
self->coro = args[0]; self->coro = args[0];
self->data = mp_const_none; self->data = mp_const_none;
self->waiting = mp_const_none; self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
self->ph_key = MP_OBJ_NEW_SMALL_INT(0); self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
if (n_args == 2) { if (n_args == 2) {
uasyncio_context = args[1]; uasyncio_context = args[1];
@ -218,24 +222,6 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel); STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
STATIC mp_obj_t task_throw(mp_obj_t self_in, mp_obj_t value_in) {
// This task raised an exception which was uncaught; handle that now.
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
// Set the data because it was cleared by the main scheduling loop.
self->data = value_in;
if (self->waiting == mp_const_none) {
// Nothing await'ed on the task so call the exception handler.
mp_obj_t _exc_context = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__exc_context));
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_exception), value_in);
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_future), self_in);
mp_obj_t Loop = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_Loop));
mp_obj_t call_exception_handler = mp_load_attr(Loop, MP_QSTR_call_exception_handler);
mp_call_function_1(call_exception_handler, _exc_context);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_throw_obj, task_throw);
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) { if (dest[0] == MP_OBJ_NULL) {
@ -244,32 +230,24 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[0] = self->coro; dest[0] = self->coro;
} else if (attr == MP_QSTR_data) { } else if (attr == MP_QSTR_data) {
dest[0] = self->data; dest[0] = self->data;
} else if (attr == MP_QSTR_waiting) { } else if (attr == MP_QSTR_state) {
if (self->waiting != mp_const_none && self->waiting != mp_const_false) { dest[0] = self->state;
dest[0] = self->waiting;
}
} else if (attr == MP_QSTR_done) { } else if (attr == MP_QSTR_done) {
dest[0] = MP_OBJ_FROM_PTR(&task_done_obj); dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
dest[1] = self_in; dest[1] = self_in;
} else if (attr == MP_QSTR_cancel) { } else if (attr == MP_QSTR_cancel) {
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj); dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
dest[1] = self_in; dest[1] = self_in;
} else if (attr == MP_QSTR_throw) {
dest[0] = MP_OBJ_FROM_PTR(&task_throw_obj);
dest[1] = self_in;
} else if (attr == MP_QSTR_ph_key) { } else if (attr == MP_QSTR_ph_key) {
dest[0] = self->ph_key; dest[0] = self->ph_key;
} }
} else if (dest[1] != MP_OBJ_NULL) { } else if (dest[1] != MP_OBJ_NULL) {
// Store // Store
if (attr == MP_QSTR_coro) { if (attr == MP_QSTR_data) {
self->coro = dest[1];
dest[0] = MP_OBJ_NULL;
} else if (attr == MP_QSTR_data) {
self->data = dest[1]; self->data = dest[1];
dest[0] = MP_OBJ_NULL; dest[0] = MP_OBJ_NULL;
} else if (attr == MP_QSTR_waiting) { } else if (attr == MP_QSTR_state) {
self->waiting = dest[1]; self->state = dest[1];
dest[0] = MP_OBJ_NULL; dest[0] = MP_OBJ_NULL;
} }
} }
@ -278,15 +256,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
(void)iter_buf; (void)iter_buf;
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (self->waiting == mp_const_none) {
// The is the first access of the "waiting" entry.
if (TASK_IS_DONE(self)) { if (TASK_IS_DONE(self)) {
// Signal that the completed-task has been await'ed on. // Signal that the completed-task has been await'ed on.
self->waiting = mp_const_false; self->state = TASK_STATE_DONE_WAS_WAITED_ON;
} else { } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
// Lazily allocate the waiting queue. // Allocate the waiting queue.
self->waiting = task_queue_make_new(&task_queue_type, 0, 0, NULL); self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
}
} }
return self_in; return self_in;
} }
@ -299,7 +274,7 @@ STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
} else { } else {
// Put calling task on waiting queue. // Put calling task on waiting queue.
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task)); mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t args[2] = { self->waiting, cur_task }; mp_obj_t args[2] = { self->state, cur_task };
task_queue_push_sorted(2, args); task_queue_push_sorted(2, args);
// Set calling task's data to this task that it waits on, to double-link it. // Set calling task's data to this task that it waits on, to double-link it.
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in; ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;

View File

@ -15,38 +15,10 @@
#if MICROPY_PY_UCTYPES #if MICROPY_PY_UCTYPES
/// \module uctypes - Access data structures in memory // The uctypes module allows defining the layout of a raw data structure (using
/// // terms of the C language), and then access memory buffers using this definition.
/// The module allows to define layout of raw data structure (using terms // The module also provides convenience functions to access memory buffers
/// of C language), and then access memory buffers using this definition. // contained in Python objects or wrap memory buffers in Python objects.
/// The module also provides convenience functions to access memory buffers
/// contained in Python objects or wrap memory buffers in Python objects.
/// \constant UINT8_1 - uint8_t value type
/// \class struct - C-like structure
///
/// Encapsulalation of in-memory data structure. This class doesn't define
/// any methods, only attribute access (for structure fields) and
/// indexing (for pointer and array fields).
///
/// Usage:
///
/// # Define layout of a structure with 2 fields
/// # 0 and 4 are byte offsets of fields from the beginning of struct
/// # they are logically ORed with field type
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
///
/// # Example memory buffer to access (contained in bytes object)
/// buf = b"\x64\0\0\0\0x14"
///
/// # Create structure object referring to address of
/// # the data in the buffer above
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
///
/// # Access fields
/// print(s.a, s.b)
/// # Result:
/// # 100, 20
#define LAYOUT_LITTLE_ENDIAN (0) #define LAYOUT_LITTLE_ENDIAN (0)
#define LAYOUT_BIG_ENDIAN (1) #define LAYOUT_BIG_ENDIAN (1)
@ -56,6 +28,7 @@
#define BITF_LEN_BITS 5 #define BITF_LEN_BITS 5
#define BITF_OFF_BITS 5 #define BITF_OFF_BITS 5
#define OFFSET_BITS 17 #define OFFSET_BITS 17
#define LEN_BITS (OFFSET_BITS + BITF_OFF_BITS)
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31 #if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
#error Invalid encoding field length #error Invalid encoding field length
#endif #endif
@ -172,7 +145,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
mp_uint_t item_s; mp_uint_t item_s;
if (t->len == 2) { if (t->len == 2) {
// Elements of array are scalar // Elements of array are scalar
item_s = GET_SCALAR_SIZE(val_type); item_s = uctypes_struct_scalar_size(val_type);
if (item_s > *max_field_size) { if (item_s > *max_field_size) {
*max_field_size = item_s; *max_field_size = item_s;
} }
@ -400,10 +373,8 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
offset &= VALUE_MASK(VAL_TYPE_BITS); offset &= VALUE_MASK(VAL_TYPE_BITS);
// printf("scalar type=%d offset=%x\n", val_type, offset);
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) { if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
if (self->flags == LAYOUT_NATIVE) { if (self->flags == LAYOUT_NATIVE) {
if (set_val == MP_OBJ_NULL) { if (set_val == MP_OBJ_NULL) {
return get_aligned(val_type, self->addr + offset, 0); return get_aligned(val_type, self->addr + offset, 0);
@ -420,9 +391,9 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
} }
} }
} else if (val_type >= BFUINT8 && val_type <= BFINT32) { } else if (val_type >= BFUINT8 && val_type <= BFINT32) {
uint bit_offset = (offset >> 17) & 31; uint bit_offset = (offset >> OFFSET_BITS) & 31;
uint bit_len = (offset >> 22) & 31; uint bit_len = (offset >> LEN_BITS) & 31;
offset &= (1 << 17) - 1; offset &= (1 << OFFSET_BITS) - 1;
mp_uint_t val; mp_uint_t val;
if (self->flags == LAYOUT_NATIVE) { if (self->flags == LAYOUT_NATIVE) {
val = get_aligned_basic(val_type & 6, self->addr + offset); val = get_aligned_basic(val_type & 6, self->addr + offset);
@ -470,7 +441,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]); mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS); mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
offset &= VALUE_MASK(AGG_TYPE_BITS); offset &= VALUE_MASK(AGG_TYPE_BITS);
// printf("agg type=%d offset=%x\n", agg_type, offset);
switch (agg_type) { switch (agg_type) {
case STRUCT: { case STRUCT: {
@ -495,7 +465,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
o->desc = MP_OBJ_FROM_PTR(sub); o->desc = MP_OBJ_FROM_PTR(sub);
o->addr = self->addr + offset; o->addr = self->addr + offset;
o->flags = self->flags; o->flags = self->flags;
// printf("PTR/ARR base addr=%p\n", o->addr);
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
} }
} }
@ -553,7 +522,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
return value; // just !MP_OBJ_NULL return value; // just !MP_OBJ_NULL
} }
} else { } else {
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index; byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
if (value == MP_OBJ_SENTINEL) { if (value == MP_OBJ_SENTINEL) {
return get_unaligned(val_type, p, self->flags); return get_unaligned(val_type, p, self->flags);
} else { } else {
@ -628,9 +597,8 @@ STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
return 0; return 0;
} }
/// \function addressof() // addressof()
/// Return address of object's data (applies to object providing buffer // Return address of object's data (applies to objects providing the buffer interface).
/// interface).
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) { STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
@ -638,25 +606,20 @@ STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
} }
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof); MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
/// \function bytearray_at() // bytearray_at()
/// Capture memory at given address of given size as bytearray. Memory is // Capture memory at given address of given size as bytearray.
/// captured by reference (and thus memory pointed by bytearray may change
/// or become invalid at later time). Use bytes_at() to capture by value.
STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) { STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr)); return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
} }
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at); MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
/// \function bytes_at() // bytes_at()
/// Capture memory at given address of given size as bytes. Memory is // Capture memory at given address of given size as bytes.
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
/// ("zero copy").
STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) { STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size)); return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
} }
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at); MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
STATIC const mp_obj_type_t uctypes_struct_type = { STATIC const mp_obj_type_t uctypes_struct_type = {
{ &mp_type_type }, { &mp_type_type },
.name = MP_QSTR_struct, .name = MP_QSTR_struct,
@ -676,81 +639,63 @@ STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) }, { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
{ MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) }, { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
/// \moduleref uctypes
/// \constant NATIVE - Native structure layout - native endianness,
/// platform-specific field alignment
{ MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) }, { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
/// (no alignment constraints)
{ MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) }, { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
/// (no alignment constraints)
{ MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) }, { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
/// \constant VOID - void value type, may be used only as pointer target type.
{ MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) }, { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
/// \constant UINT8 - uint8_t value type { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) }, { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
/// \constant INT8 - int8_t value type { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) }, { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
/// \constant UINT16 - uint16_t value type { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
/// \constant INT16 - int16_t value type { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
/// \constant UINT32 - uint32_t value type
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
/// \constant INT32 - int32_t value type
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
/// \constant UINT64 - uint64_t value type
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
/// \constant INT64 - int64_t value type
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) }, { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) }, { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) }, { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
#endif #endif
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES #if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
// C native type aliases. These depend on GCC-compatible predefined // C native type aliases. These depend on GCC-compatible predefined
// preprocessor macros. // preprocessor macros.
#if __SIZEOF_SHORT__ == 2 #if __SIZEOF_SHORT__ == 2
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) }, { MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
#endif #endif
#if __SIZEOF_INT__ == 4 #if __SIZEOF_INT__ == 4
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
#endif #endif
#if __SIZEOF_LONG__ == 4 #if __SIZEOF_LONG__ == 4
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
#elif __SIZEOF_LONG__ == 8 #elif __SIZEOF_LONG__ == 8
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
#endif #endif
#if __SIZEOF_LONG_LONG__ == 8 #if __SIZEOF_LONG_LONG__ == 8
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, { MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, { MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
#endif #endif
#endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES #endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) }, { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) }, { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
}; };
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table); STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
const mp_obj_module_t mp_module_uctypes = { const mp_obj_module_t mp_module_uctypes = {

View File

@ -42,9 +42,16 @@
typedef struct _mp_obj_hash_t { typedef struct _mp_obj_hash_t {
mp_obj_base_t base; mp_obj_base_t base;
char state[0]; bool final; // if set, update and digest raise an exception
uintptr_t state[0]; // must be aligned to a machine word
} mp_obj_hash_t; } mp_obj_hash_t;
static void uhashlib_ensure_not_final(mp_obj_hash_t *self) {
if (self->final) {
mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
}
}
#if MICROPY_PY_UHASHLIB_SHA256 #if MICROPY_PY_UHASHLIB_SHA256
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg); STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
@ -60,6 +67,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
o->base.type = type; o->base.type = type;
o->final = false;
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state); mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0); mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
if (n_args == 1) { if (n_args == 1) {
@ -70,6 +78,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len); mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
@ -78,6 +87,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, 32); vstr_init_len(&vstr, 32);
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf); mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
@ -102,6 +113,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
mp_arg_check_num(n_args, kw_args, 0, 1, false); mp_arg_check_num(n_args, kw_args, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
o->base.type = type; o->base.type = type;
o->final = false;
sha256_init((CRYAL_SHA256_CTX *)o->state); sha256_init((CRYAL_SHA256_CTX *)o->state);
if (n_args == 1) { if (n_args == 1) {
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]); uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
@ -112,6 +124,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg); check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len); sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
@ -120,6 +133,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, SHA256_BLOCK_SIZE); vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf); sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
@ -153,6 +168,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
mp_arg_check_num(n_args, kw_args, 0, 1, false); mp_arg_check_num(n_args, kw_args, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
o->base.type = type; o->base.type = type;
o->final = false;
SHA1_Init((SHA1_CTX *)o->state); SHA1_Init((SHA1_CTX *)o->state);
if (n_args == 1) { if (n_args == 1) {
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]); uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
@ -163,6 +179,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg); check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len); SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
@ -171,6 +188,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, SHA1_SIZE); vstr_init_len(&vstr, SHA1_SIZE);
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state); SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
@ -190,6 +209,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
o->base.type = type; o->base.type = type;
o->final = false;
mbedtls_sha1_init((mbedtls_sha1_context *)o->state); mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state); mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
if (n_args == 1) { if (n_args == 1) {
@ -200,6 +220,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len); mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
@ -208,6 +229,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, 20); vstr_init_len(&vstr, 20);
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf); mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
@ -241,6 +264,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
o->base.type = type; o->base.type = type;
o->final = false;
MD5_Init((MD5_CTX *)o->state); MD5_Init((MD5_CTX *)o->state);
if (n_args == 1) { if (n_args == 1) {
uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]); uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
@ -250,6 +274,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len); MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
@ -258,6 +283,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, MD5_SIZE); vstr_init_len(&vstr, MD5_SIZE);
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state); MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
@ -277,6 +304,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context)); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
o->base.type = type; o->base.type = type;
o->final = false;
mbedtls_md5_init((mbedtls_md5_context *)o->state); mbedtls_md5_init((mbedtls_md5_context *)o->state);
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state); mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
if (n_args == 1) { if (n_args == 1) {
@ -287,6 +315,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) { STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len); mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
@ -295,6 +324,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) { STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
uhashlib_ensure_not_final(self);
self->final = true;
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, 16); vstr_init_len(&vstr, 16);
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf); mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);

View File

@ -66,8 +66,11 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) {
STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) { STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
int n = mp_obj_get_int(num_in); int n = mp_obj_get_int(num_in);
if (n > 32 || n == 0) { if (n > 32 || n < 0) {
mp_raise_ValueError(NULL); mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
}
if (n == 0) {
return MP_OBJ_NEW_SMALL_INT(0);
} }
uint32_t mask = ~0; uint32_t mask = ~0;
// Beware of C undefined behavior when shifting by >= than bit size // Beware of C undefined behavior when shifting by >= than bit size

View File

@ -20,10 +20,6 @@
// Flags for poll() // Flags for poll()
#define FLAG_ONESHOT (1) #define FLAG_ONESHOT (1)
/// \module select - Provides select function to wait for events on a stream
///
/// This module provides the select function.
typedef struct _poll_obj_t { typedef struct _poll_obj_t {
mp_obj_t obj; mp_obj_t obj;
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
@ -91,7 +87,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
return n_ready; return n_ready;
} }
/// \function select(rlist, wlist, xlist[, timeout]) // select(rlist, wlist, xlist[, timeout])
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
// get array data from tuple/list arguments // get array data from tuple/list arguments
size_t rwx_len[3]; size_t rwx_len[3];
@ -158,8 +154,6 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
/// \class Poll - poll class
typedef struct _mp_obj_poll_t { typedef struct _mp_obj_poll_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_map_t poll_map; mp_map_t poll_map;
@ -170,7 +164,7 @@ typedef struct _mp_obj_poll_t {
mp_obj_t ret_tuple; mp_obj_t ret_tuple;
} mp_obj_poll_t; } mp_obj_poll_t;
/// \method register(obj[, eventmask]) // register(obj[, eventmask])
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
mp_uint_t flags; mp_uint_t flags;
@ -184,7 +178,7 @@ STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
/// \method unregister(obj) // unregister(obj)
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) { STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND); mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
@ -193,7 +187,7 @@ STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
} }
MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister); MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
/// \method modify(obj, eventmask) // modify(obj, eventmask)
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) { STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP); mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
@ -328,7 +322,7 @@ STATIC const mp_obj_type_t mp_type_poll = {
.locals_dict = (void *)&poll_locals_dict, .locals_dict = (void *)&poll_locals_dict,
}; };
/// \function poll() // poll()
STATIC mp_obj_t select_poll(void) { STATIC mp_obj_t select_poll(void) {
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t); mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
poll->base.type = &mp_type_poll; poll->base.type = &mp_type_poll;

View File

@ -175,6 +175,10 @@ def run_until_complete(main_task=None):
if not exc: if not exc:
t.coro.send(None) t.coro.send(None)
else: else:
# If the task is finished and on the run queue and gets here, then it
# had an exception and was not await'ed on. Throwing into it now will
# raise StopIteration and the code below will catch this and run the
# call_exception_handler function.
t.data = None t.data = None
t.coro.throw(exc) t.coro.throw(exc)
except excs_all as er: except excs_all as er:
@ -185,22 +189,32 @@ def run_until_complete(main_task=None):
if isinstance(er, StopIteration): if isinstance(er, StopIteration):
return er.value return er.value
raise er raise er
# Schedule any other tasks waiting on the completion of this task if t.state:
# Task was running but is now finished.
waiting = False waiting = False
if hasattr(t, "waiting"): if t.state is True:
while t.waiting.peek(): # "None" indicates that the task is complete and not await'ed on (yet).
_task_queue.push_head(t.waiting.pop_head()) t.state = None
else:
# Schedule any other tasks waiting on the completion of this task.
while t.state.peek():
_task_queue.push_head(t.state.pop_head())
waiting = True waiting = True
t.waiting = None # Free waiting queue head # "False" indicates that the task is complete and has been await'ed on.
t.state = False
if not waiting and not isinstance(er, excs_stop): if not waiting and not isinstance(er, excs_stop):
# An exception ended this detached task, so queue it for later # An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves # execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw). # the exception in the meantime (this is handled by Task.throw).
_task_queue.push_head(t) _task_queue.push_head(t)
# Indicate task is done by setting coro to the task object itself # Save return value of coro to pass up to caller.
t.coro = t
# Save return value of coro to pass up to caller
t.data = er t.data = er
elif t.state is None:
# Task is already finished and nothing await'ed on the task,
# so call the exception handler.
_exc_context["exception"] = exc
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# Create a new task from a coroutine and run it until it finishes # Create a new task from a coroutine and run it until it finishes

View File

@ -30,6 +30,10 @@ class Stream:
yield core._io_queue.queue_read(self.s) yield core._io_queue.queue_read(self.s)
return self.s.read(n) return self.s.read(n)
async def readinto(self, buf):
yield core._io_queue.queue_read(self.s)
return self.s.readinto(buf)
async def readexactly(self, n): async def readexactly(self, n):
r = b"" r = b""
while n: while n:
@ -82,7 +86,7 @@ async def open_connection(host, port):
try: try:
s.connect(ai[-1]) s.connect(ai[-1])
except OSError as er: except OSError as er:
if er.args[0] != EINPROGRESS: if er.errno != EINPROGRESS:
raise er raise er
yield core._io_queue.queue_write(s) yield core._io_queue.queue_write(s)
return ss, ss return ss, ss
@ -112,7 +116,6 @@ class Server:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(ai[-1]) s.bind(ai[-1])
s.listen(backlog) s.listen(backlog)
self.task = core.cur_task
# Accept incoming connections # Accept incoming connections
while True: while True:
try: try:
@ -135,7 +138,7 @@ class Server:
# TODO could use an accept-callback on socket read activity instead of creating a task # TODO could use an accept-callback on socket read activity instead of creating a task
async def start_server(cb, host, port, backlog=5): async def start_server(cb, host, port, backlog=5):
s = Server() s = Server()
core.create_task(s._serve(cb, host, port, backlog)) s.task = core.create_task(s._serve(cb, host, port, backlog))
return s return s

View File

@ -123,6 +123,7 @@ class Task:
def __init__(self, coro, globals=None): def __init__(self, coro, globals=None):
self.coro = coro # Coroutine of this Task self.coro = coro # Coroutine of this Task
self.data = None # General data for queue it is waiting on self.data = None # General data for queue it is waiting on
self.state = True # None, False, True or a TaskQueue instance
self.ph_key = 0 # Pairing heap self.ph_key = 0 # Pairing heap
self.ph_child = None # Paring heap self.ph_child = None # Paring heap
self.ph_child_last = None # Paring heap self.ph_child_last = None # Paring heap
@ -130,30 +131,30 @@ class Task:
self.ph_rightmost_parent = None # Paring heap self.ph_rightmost_parent = None # Paring heap
def __iter__(self): def __iter__(self):
if self.coro is self: if not self.state:
# Signal that the completed-task has been await'ed on. # Task finished, signal that is has been await'ed on.
self.waiting = None self.state = False
elif not hasattr(self, "waiting"): elif self.state is True:
# Lazily allocated head of linked list of Tasks waiting on completion of this task. # Allocated head of linked list of Tasks waiting on completion of this task.
self.waiting = TaskQueue() self.state = TaskQueue()
return self return self
def __next__(self): def __next__(self):
if self.coro is self: if not self.state:
# Task finished, raise return value to caller so it can continue. # Task finished, raise return value to caller so it can continue.
raise self.data raise self.data
else: else:
# Put calling task on waiting queue. # Put calling task on waiting queue.
self.waiting.push_head(core.cur_task) self.state.push_head(core.cur_task)
# Set calling task's data to this task that it waits on, to double-link it. # Set calling task's data to this task that it waits on, to double-link it.
core.cur_task.data = self core.cur_task.data = self
def done(self): def done(self):
return self.coro is self return not self.state
def cancel(self): def cancel(self):
# Check if task is already finished. # Check if task is already finished.
if self.coro is self: if not self.state:
return False return False
# Can't cancel self (not supported yet). # Can't cancel self (not supported yet).
if self is core.cur_task: if self is core.cur_task:
@ -172,13 +173,3 @@ class Task:
core._task_queue.push_head(self) core._task_queue.push_head(self)
self.data = core.CancelledError self.data = core.CancelledError
return True return True
def throw(self, value):
# This task raised an exception which was uncaught; handle that now.
# Set the data because it was cleared by the main scheduling loop.
self.data = value
if not hasattr(self, "waiting"):
# Nothing await'ed on the task so call the exception handler.
core._exc_context["exception"] = value
core._exc_context["future"] = self
core.Loop.call_exception_handler(core._exc_context)

View File

@ -264,7 +264,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
/// Change current directory. // Change current directory.
STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
const char *path; const char *path;
@ -280,7 +280,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
/// Get the current directory. // Get the current directory.
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
char buf[MICROPY_ALLOC_PATH_MAX + 1]; char buf[MICROPY_ALLOC_PATH_MAX + 1];
@ -292,8 +292,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
/// \function stat(path) // Get the status of a file or directory.
/// Get the status of a file or directory.
STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
const char *path = mp_obj_str_get_str(path_in); const char *path = mp_obj_str_get_str(path_in);

View File

@ -622,8 +622,8 @@ friendly_repl_reset:
// If the GC is locked at this point there is no way out except a reset, // If the GC is locked at this point there is no way out except a reset,
// so force the GC to be unlocked to help the user debug what went wrong. // so force the GC to be unlocked to help the user debug what went wrong.
if (MP_STATE_MEM(gc_lock_depth) != 0) { if (MP_STATE_THREAD(gc_lock_depth) != 0) {
MP_STATE_MEM(gc_lock_depth) = 0; MP_STATE_THREAD(gc_lock_depth) = 0;
} }
vstr_reset(&line); vstr_reset(&line);

View File

@ -47,9 +47,8 @@ extern pyexec_mode_kind_t pyexec_mode_kind;
extern int pyexec_system_exit; extern int pyexec_system_exit;
#define PYEXEC_FORCED_EXIT (0x100) #define PYEXEC_FORCED_EXIT (0x100)
#define PYEXEC_SWITCH_MODE (0x200) #define PYEXEC_EXCEPTION (0x200)
#define PYEXEC_EXCEPTION (0x400) #define PYEXEC_DEEP_SLEEP (0x400)
#define PYEXEC_DEEP_SLEEP (0x800)
int pyexec_raw_repl(void); int pyexec_raw_repl(void);
int pyexec_friendly_repl(void); int pyexec_friendly_repl(void);

132
lib/utils/semihosting.c Normal file
View File

@ -0,0 +1,132 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Ayke van Laethem
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "semihosting.h"
// Resources:
// http://embed.rs/articles/2016/semi-hosting-rust/
// https://wiki.dlang.org/Minimal_semihosted_ARM_Cortex-M_%22Hello_World%22
// https://github.com/arduino/OpenOCD/blob/master/src/target/arm_semihosting.c
#define SYS_OPEN 0x01
#define SYS_WRITEC 0x03
#define SYS_WRITE 0x05
#define SYS_READC 0x07
// Constants:
#define OPEN_MODE_READ (0) // mode "r"
#define OPEN_MODE_WRITE (4) // mode "w"
#ifndef __thumb__
#error Semihosting is only implemented for ARM microcontrollers.
#endif
static int mp_semihosting_stdout;
static uint32_t mp_semihosting_call(uint32_t num, const void *arg) {
// A semihosting call works as follows, similar to a SVCall:
// * the call is invoked by a special breakpoint: 0xAB
// * the command is placed in r0
// * a pointer to the arguments is placed in r1
// * the return value is placed in r0
// Note that because it uses the breakpoint instruction, applications
// will hang if they're not connected to a debugger. And they'll be
// stuck in a breakpoint if semihosting is not specifically enabled in
// the debugger.
// Also note that semihosting is extremely slow (sometimes >100ms per
// call).
register uint32_t num_reg __asm__ ("r0") = num;
register const void *args_reg __asm__ ("r1") = arg;
__asm__ __volatile__ (
"bkpt 0xAB\n" // invoke semihosting call
: "+r" (num_reg) // call number and result
: "r" (args_reg) // arguments
: "memory"); // make sure args aren't optimized away
return num_reg; // r0, which became the result
}
static int mp_semihosting_open_console(uint32_t mode) {
struct {
char *name;
uint32_t mode;
uint32_t name_len;
} args = {
.name = ":tt", // magic path to console
.mode = mode, // e.g. "r", "w" (see OPEN_MODE_* constants)
.name_len = 3, // strlen(":tt")
};
return mp_semihosting_call(SYS_OPEN, &args);
}
void mp_semihosting_init() {
mp_semihosting_stdout = mp_semihosting_open_console(OPEN_MODE_WRITE);
}
int mp_semihosting_rx_char() {
return mp_semihosting_call(SYS_READC, NULL);
}
static void mp_semihosting_tx_char(char c) {
mp_semihosting_call(SYS_WRITEC, &c);
}
uint32_t mp_semihosting_tx_strn(const char *str, size_t len) {
if (len == 0) {
return 0; // nothing to do
}
if (len == 1) {
mp_semihosting_tx_char(*str); // maybe faster?
return 0;
}
struct {
uint32_t fd;
const char *str;
uint32_t len;
} args = {
.fd = mp_semihosting_stdout,
.str = str,
.len = len,
};
return mp_semihosting_call(SYS_WRITE, &args);
}
uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len) {
// Write chunks of data until (excluding) the first '\n' character,
// insert a '\r' character, and then continue with the next chunk
// (starting with '\n').
// Doing byte-by-byte writes would be easier to implement but is far
// too slow.
size_t start = 0;
for (size_t i = 0; i < len; i++) {
if (str[i] == '\n') {
mp_semihosting_tx_strn(str + start, i - start);
mp_semihosting_tx_char('\r');
start = i;
}
}
return mp_semihosting_tx_strn(str + start, len - start);
}

View File

@ -2547,6 +2547,10 @@ msgstr ""
msgid "binary op %q not implemented" msgid "binary op %q not implemented"
msgstr "" msgstr ""
#: extmod/modurandom.c
msgid "bits must be 32 or less"
msgstr ""
#: shared-bindings/busio/UART.c #: shared-bindings/busio/UART.c
msgid "bits must be in range 5 to 9" msgid "bits must be in range 5 to 9"
msgstr "" msgstr ""
@ -3158,6 +3162,10 @@ msgstr ""
msgid "graphic must be 2048 bytes long" msgid "graphic must be 2048 bytes long"
msgstr "" msgstr ""
#: extmod/moduhashlib.c
msgid "hash is final"
msgstr ""
#: extmod/moduheapq.c #: extmod/moduheapq.c
msgid "heap must be a list" msgid "heap must be a list"
msgstr "" msgstr ""

View File

@ -120,7 +120,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
// Compare mp_interrupt_char with wanted_char and ignore if not matched // Compare mp_interrupt_char with wanted_char and ignore if not matched
if (mp_interrupt_char == wanted_char) { if (mp_interrupt_char == wanted_char) {
tud_cdc_read_flush(); // flush read fifo tud_cdc_read_flush(); // flush read fifo
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
// CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB. // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB.
// So, we must notify the other task when a CTRL-C is received. // So, we must notify the other task when a CTRL-C is received.
xTaskNotifyGive(circuitpython_task); xTaskNotifyGive(circuitpython_task);

View File

@ -81,7 +81,7 @@ STATIC void on_ble_evt(ble_evt_t *ble_evt, void *param) {
for (size_t i = 0; i < write->len; ++i) { for (size_t i = 0; i < write->len; ++i) {
#if MICROPY_KBD_EXCEPTION #if MICROPY_KBD_EXCEPTION
if (write->data[i] == mp_interrupt_char) { if (write->data[i] == mp_interrupt_char) {
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
} else } else
#endif #endif
{ {

View File

@ -355,7 +355,7 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *handle) {
if (context->sigint_enabled) { if (context->sigint_enabled) {
if (context->rx_char == CHAR_CTRL_C) { if (context->rx_char == CHAR_CTRL_C) {
common_hal_busio_uart_clear_rx_buffer(context); common_hal_busio_uart_clear_rx_buffer(context);
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
} }
} }

View File

@ -270,6 +270,13 @@ STATIC mp_obj_t extra_coverage(void) {
size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str); size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str);
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str); mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
len = mp_repl_autocomplete("i", 1, &mp_plat_print, &str);
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
mp_repl_autocomplete("import ", 7, &mp_plat_print, &str);
len = mp_repl_autocomplete("import ut", 9, &mp_plat_print, &str);
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
mp_repl_autocomplete("import utime", 12, &mp_plat_print, &str);
mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0))); mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)));
mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str); mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str);
len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str); len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str);
@ -485,7 +492,7 @@ STATIC mp_obj_t extra_coverage(void) {
} }
// setting the keyboard interrupt and raising it during mp_handle_pending // setting the keyboard interrupt and raising it during mp_handle_pending
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_handle_pending(true); mp_handle_pending(true);
@ -495,13 +502,13 @@ STATIC mp_obj_t extra_coverage(void) {
} }
// setting the keyboard interrupt (twice) and cancelling it during mp_handle_pending // setting the keyboard interrupt (twice) and cancelling it during mp_handle_pending
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
mp_handle_pending(false); mp_handle_pending(false);
// setting keyboard interrupt and a pending event (intr should be handled first) // setting keyboard interrupt and a pending event (intr should be handled first)
mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(10)); mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(10));
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_handle_pending(true); mp_handle_pending(true);
nlr_pop(); nlr_pop();

View File

@ -450,7 +450,13 @@ MP_NOINLINE int main_(int argc, char **argv) {
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
#endif #endif
mp_stack_set_limit(40000 * (sizeof(void *) / 4)); // Define a reasonable stack limit to detect stack overflow.
mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
#if defined(__arm__) && !defined(__thumb2__)
// ARM (non-Thumb) architectures require more stack.
stack_limit *= 2;
#endif
mp_stack_set_limit(stack_limit);
pre_process_options(argc, argv); pre_process_options(argc, argv);

View File

@ -35,6 +35,7 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/binary.h" #include "py/binary.h"
#include "py/mperrno.h" #include "py/mperrno.h"
#include "py/objint.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
@ -58,6 +59,18 @@
* but may be later. * but may be later.
*/ */
// This union is large enough to hold any supported argument/return value.
typedef union _ffi_union_t {
ffi_arg ffi;
unsigned char B;
unsigned short int H;
unsigned int I;
unsigned long int L;
unsigned long long int Q;
float flt;
double dbl;
} ffi_union_t;
typedef struct _mp_obj_opaque_t { typedef struct _mp_obj_opaque_t {
mp_obj_base_t base; mp_obj_base_t base;
void *val; void *val;
@ -153,10 +166,10 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) {
mp_raise_TypeError(MP_ERROR_TEXT("unknown type")); mp_raise_TypeError(MP_ERROR_TEXT("unknown type"));
} }
STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) { STATIC mp_obj_t return_ffi_value(ffi_union_t *val, char type) {
switch (type) { switch (type) {
case 's': { case 's': {
const char *s = (const char *)(intptr_t)val; const char *s = (const char *)(intptr_t)val->ffi;
if (!s) { if (!s) {
return mp_const_none; return mp_const_none;
} }
@ -166,20 +179,30 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
return mp_const_none; return mp_const_none;
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
case 'f': { case 'f': {
union { ffi_arg ffi; return mp_obj_new_float_from_f(val->flt);
float flt;
} val_union = { .ffi = val };
return mp_obj_new_float_from_f(val_union.flt);
} }
case 'd': { case 'd': {
double *p = (double *)&val; return mp_obj_new_float_from_d(val->dbl);
return mp_obj_new_float_from_d(*p);
} }
#endif #endif
case 'b':
case 'h':
case 'i':
case 'l':
return mp_obj_new_int((signed)val->ffi);
case 'B':
case 'H':
case 'I':
case 'L':
return mp_obj_new_int_from_uint(val->ffi);
case 'q':
return mp_obj_new_int_from_ll(val->Q);
case 'Q':
return mp_obj_new_int_from_ull(val->Q);
case 'O': case 'O':
return (mp_obj_t)(intptr_t)val; return (mp_obj_t)(intptr_t)val->ffi;
default: default:
return mp_obj_new_int(val); return mp_obj_new_int(val->ffi);
} }
} }
@ -364,34 +387,74 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
mp_printf(print, "<ffifunc %p>", self->func); mp_printf(print, "<ffifunc %p>", self->func);
} }
STATIC unsigned long long ffi_get_int_value(mp_obj_t o) {
if (mp_obj_is_small_int(o)) {
return MP_OBJ_SMALL_INT_VALUE(o);
} else {
unsigned long long res;
mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
return res;
}
}
STATIC ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
ffi_union_t ret;
if ((argtype | 0x20) == 'q') {
ret.Q = ffi_get_int_value(o);
return ret;
} else {
mp_uint_t val = mp_obj_int_get_truncated(o);
switch (argtype) {
case 'b':
case 'B':
ret.B = val;
break;
case 'h':
case 'H':
ret.H = val;
break;
case 'i':
case 'I':
ret.I = val;
break;
case 'l':
case 'L':
ret.L = val;
break;
default:
ret.ffi = val;
break;
}
}
return ret;
}
STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
(void)n_kw; (void)n_kw;
mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
assert(n_kw == 0); assert(n_kw == 0);
assert(n_args == self->cif.nargs); assert(n_args == self->cif.nargs);
ffi_arg values[n_args]; ffi_union_t values[n_args];
void *valueptrs[n_args]; void *valueptrs[n_args];
const char *argtype = self->argtypes; const char *argtype = self->argtypes;
for (uint i = 0; i < n_args; i++, argtype++) { for (uint i = 0; i < n_args; i++, argtype++) {
mp_obj_t a = args[i]; mp_obj_t a = args[i];
if (*argtype == 'O') { if (*argtype == 'O') {
values[i] = (ffi_arg)(intptr_t)a; values[i].ffi = (ffi_arg)(intptr_t)a;
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
} else if (*argtype == 'f') { } else if (*argtype == 'f') {
float *p = (float *)&values[i]; values[i].flt = mp_obj_get_float_to_f(a);
*p = mp_obj_get_float_to_f(a);
} else if (*argtype == 'd') { } else if (*argtype == 'd') {
double *p = (double *)&values[i]; values[i].dbl = mp_obj_get_float_to_d(a);
*p = mp_obj_get_float_to_d(a);
#endif #endif
} else if (a == mp_const_none) { } else if (a == mp_const_none) {
values[i] = 0; values[i].ffi = 0;
} else if (mp_obj_is_int(a)) { } else if (mp_obj_is_int(a)) {
values[i] = mp_obj_int_get_truncated(a); values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
} else if (mp_obj_is_str(a)) { } else if (mp_obj_is_str(a)) {
const char *s = mp_obj_str_get_str(a); const char *s = mp_obj_str_get_str(a);
values[i] = (ffi_arg)(intptr_t)s; values[i].ffi = (ffi_arg)(intptr_t)s;
} else if (((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) { } else if (((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) {
mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a); mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
@ -399,32 +462,19 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
if (ret != 0) { if (ret != 0) {
goto error; goto error;
} }
values[i] = (ffi_arg)(intptr_t)bufinfo.buf; values[i].ffi = (ffi_arg)(intptr_t)bufinfo.buf;
} else if (mp_obj_is_type(a, &fficallback_type)) { } else if (mp_obj_is_type(a, &fficallback_type)) {
mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a); mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);
values[i] = (ffi_arg)(intptr_t)p->func; values[i].ffi = (ffi_arg)(intptr_t)p->func;
} else { } else {
goto error; goto error;
} }
valueptrs[i] = &values[i]; valueptrs[i] = &values[i];
} }
// If ffi_arg is not big enough to hold a double, then we must pass along a ffi_union_t retval;
// pointer to a memory location of the correct size.
// TODO check if this needs to be done for other types which don't fit into
// ffi_arg.
#if MICROPY_PY_BUILTINS_FLOAT
if (sizeof(ffi_arg) == 4 && self->rettype == 'd') {
double retval;
ffi_call(&self->cif, self->func, &retval, valueptrs); ffi_call(&self->cif, self->func, &retval, valueptrs);
return mp_obj_new_float_from_d(retval); return return_ffi_value(&retval, self->rettype);
} else
#endif
{
ffi_arg retval;
ffi_call(&self->cif, self->func, &retval, valueptrs);
return return_ffi_value(retval, self->rettype);
}
error: error:
mp_raise_TypeError(MP_ERROR_TEXT("Don't know how to pass object to native function")); mp_raise_TypeError(MP_ERROR_TEXT("Don't know how to pass object to native function"));

View File

@ -126,7 +126,7 @@ void mp_thread_init(void) {
thread->next = NULL; thread->next = NULL;
#if defined(__APPLE__) #if defined(__APPLE__)
snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%d", (int)thread->id); snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%ld", (long)thread->id);
thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0); thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0);
#else #else
sem_init(&thread_signal_done, 0, 0); sem_init(&thread_signal_done, 0, 0);

View File

@ -57,7 +57,7 @@ STATIC void sighandler(int signum) {
// this is the second time we are called, so die straight away // this is the second time we are called, so die straight away
exit(1); exit(1);
} }
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
#endif #endif
} }
} }

View File

@ -40,7 +40,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
size_t n_args_max = (sig >> 1) & 0xffff; size_t n_args_max = (sig >> 1) & 0xffff;
if (n_kw && !takes_kw) { if (n_kw && !takes_kw) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError(MP_ERROR_TEXT("function doesn't take keyword arguments")); mp_raise_TypeError(MP_ERROR_TEXT("function doesn't take keyword arguments"));
@ -49,7 +49,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
if (n_args_min == n_args_max) { if (n_args_min == n_args_max) {
if (n_args != n_args_min) { if (n_args != n_args_min) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("function takes %d positional arguments but %d were given"), mp_raise_TypeError_varg(MP_ERROR_TEXT("function takes %d positional arguments but %d were given"),
@ -58,7 +58,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
} }
} else { } else {
if (n_args < n_args_min) { if (n_args < n_args_min) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -66,7 +66,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
n_args_min - n_args); n_args_min - n_args);
#endif #endif
} else if (n_args > n_args_max) { } else if (n_args > n_args_max) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -106,7 +106,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
} }
if (kw == NULL) { if (kw == NULL) {
if (allowed[i].flags & MP_ARG_REQUIRED) { if (allowed[i].flags & MP_ARG_REQUIRED) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst); mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst);
@ -130,7 +130,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
} }
if (pos_found < n_pos) { if (pos_found < n_pos) {
extra_positional: extra_positional:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
// TODO better error message // TODO better error message
@ -138,7 +138,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
#endif #endif
} }
if (kws != NULL && kws_found < kws->used) { if (kws != NULL && kws_found < kws->used) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
// TODO better error message // TODO better error message

View File

@ -38,25 +38,6 @@
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) #define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
void asm_arm_end_pass(asm_arm_t *as) {
if (as->base.pass == MP_ASM_PASS_EMIT) {
#if defined(__linux__) && defined(__GNUC__)
char *start = mp_asm_base_get_code(&as->base);
char *end = start + mp_asm_base_get_code_size(&as->base);
__builtin___clear_cache(start, end);
#elif defined(__arm__)
// flush I- and D-cache
asm volatile (
"0:"
"mrc p15, 0, r15, c7, c10, 3\n"
"bne 0b\n"
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c7, 0\n"
: : : "r0", "cc");
#endif
}
}
// Insert word into instruction flow // Insert word into instruction flow
STATIC void emit(asm_arm_t *as, uint op) { STATIC void emit(asm_arm_t *as, uint op) {
uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);

View File

@ -72,7 +72,9 @@ typedef struct _asm_arm_t {
uint stack_adjust; uint stack_adjust;
} asm_arm_t; } asm_arm_t;
void asm_arm_end_pass(asm_arm_t *as); static inline void asm_arm_end_pass(asm_arm_t *as) {
(void)as;
}
void asm_arm_entry(asm_arm_t *as, int num_locals); void asm_arm_entry(asm_arm_t *as, int num_locals);
void asm_arm_exit(asm_arm_t *as); void asm_arm_exit(asm_arm_t *as);

View File

@ -35,7 +35,6 @@
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/persistentcode.h" #include "py/persistentcode.h"
#include "py/mphal.h"
#include "py/asmthumb.h" #include "py/asmthumb.h"
#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) #define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32)
@ -62,20 +61,6 @@ static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
return mp_asm_base_get_cur_to_write_bytes(&as->base, n); return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
} }
void asm_thumb_end_pass(asm_thumb_t *as) {
(void)as;
// could check labels are resolved...
#if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1
if (as->base.pass == MP_ASM_PASS_EMIT) {
// flush D-cache, so the code emitted is stored in memory
MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size);
// invalidate I-cache
SCB_InvalidateICache();
}
#endif
}
/* /*
STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) { STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {
byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); byte *c = asm_thumb_get_cur_to_write_bytes(as, 1);

View File

@ -70,7 +70,9 @@ typedef struct _asm_thumb_t {
uint32_t stack_adjust; uint32_t stack_adjust;
} asm_thumb_t; } asm_thumb_t;
void asm_thumb_end_pass(asm_thumb_t *as); static inline void asm_thumb_end_pass(asm_thumb_t *as) {
(void)as;
}
void asm_thumb_entry(asm_thumb_t *as, int num_locals); void asm_thumb_entry(asm_thumb_t *as, int num_locals);
void asm_thumb_exit(asm_thumb_t *as); void asm_thumb_exit(asm_thumb_t *as);

View File

@ -285,31 +285,28 @@ void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest
} }
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
assert(src_r64 < 8); if (src_r64 < 8 && dest_r64 < 8) {
if (dest_r64 < 8) {
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64); asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
} else { } else {
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64); asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM8_TO_R64);
} }
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
} }
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
assert(src_r64 < 8); if (src_r64 < 8 && dest_r64 < 8) {
if (dest_r64 < 8) {
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64); asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
} else { } else {
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64); asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM16_TO_R64);
} }
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
} }
void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) { void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
assert(src_r64 < 8); if (src_r64 < 8 && dest_r64 < 8) {
if (dest_r64 < 8) {
asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64); asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64);
} else { } else {
asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_TO_R64); asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64);
} }
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp); asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
} }

View File

@ -77,7 +77,7 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
#endif #endif
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
// generic message, used also for other argument issues // generic message, used also for other argument issues
(void)f; (void)f;
(void)expected; (void)expected;
@ -221,7 +221,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
} }
// Didn't find name match with positional args // Didn't find name match with positional args
if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument")); mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(

View File

@ -332,7 +332,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
// We must have some component left over to import from // We must have some component left over to import from
if (p == this_name) { if (p == this_name) {
mp_raise_ValueError(MP_ERROR_TEXT("cannot perform relative import")); mp_raise_ImportError(MP_ERROR_TEXT("cannot perform relative import"));
} }
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
@ -421,7 +421,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
mp_module_call_init(mod_name, module_obj); mp_module_call_init(mod_name, module_obj);
} else { } else {
// couldn't find the file, so fail // couldn't find the file, so fail
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ImportError(MP_ERROR_TEXT("module not found")); mp_raise_ImportError(MP_ERROR_TEXT("module not found"));
#else #else
mp_raise_msg_varg(&mp_type_ImportError, mp_raise_msg_varg(&mp_type_ImportError,
@ -533,7 +533,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
#endif #endif
// Couldn't find the module, so fail // Couldn't find the module, so fail
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found")); mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
#else #else
mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr); mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr);

View File

@ -1795,16 +1795,6 @@ STATIC void compile_yield_from(compiler_t *comp) {
} }
#if MICROPY_PY_ASYNC_AWAIT #if MICROPY_PY_ASYNC_AWAIT
STATIC bool compile_require_async_context(compiler_t *comp, mp_parse_node_struct_t *pns) {
int scope_flags = comp->scope_cur->scope_flags;
if ((scope_flags & MP_SCOPE_FLAG_ASYNC) != 0) {
return true;
}
compile_syntax_error(comp, (mp_parse_node_t)pns,
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
return false;
}
STATIC void compile_await_object_method(compiler_t *comp, qstr method) { STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
EMIT_ARG(load_method, method, false); EMIT_ARG(load_method, method, false);
EMIT_ARG(call_method, 0, 0, 0); EMIT_ARG(call_method, 0, 0, 0);
@ -1813,11 +1803,6 @@ STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// comp->break_label |= MP_EMIT_BREAK_FROM_FOR; // comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
if (!compile_require_async_context(comp, pns)) {
return;
}
qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]); qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
uint while_else_label = comp_next_label(comp); uint while_else_label = comp_next_label(comp);
uint try_exception_label = comp_next_label(comp); uint try_exception_label = comp_next_label(comp);
@ -1980,9 +1965,6 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_
} }
STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (!compile_require_async_context(comp, pns)) {
return;
}
// get the nodes for the pre-bit of the with (the a as b, c as d, ... bit) // get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
mp_parse_node_t *nodes; mp_parse_node_t *nodes;
size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes); size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
@ -2000,7 +1982,16 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_funcdef(comp, pns0); compile_funcdef(comp, pns0);
scope_t *fscope = (scope_t *)pns0->nodes[4]; scope_t *fscope = (scope_t *)pns0->nodes[4];
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC; fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) { } else {
// async for/with; first verify the scope is a generator
int scope_flags = comp->scope_cur->scope_flags;
if (!(scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
compile_syntax_error(comp, (mp_parse_node_t)pns0,
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
return;
}
if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
// async for // async for
compile_async_for_stmt(comp, pns0); compile_async_for_stmt(comp, pns0);
} else { } else {
@ -2009,6 +2000,7 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_async_with_stmt(comp, pns0); compile_async_with_stmt(comp, pns0);
} }
} }
}
#endif #endif
STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
@ -2627,7 +2619,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
compile_node(comp, pn_i); compile_node(comp, pn_i);
if (is_dict) { if (is_dict) {
if (!is_key_value) { if (!is_key_value) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax")); compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
#else #else
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting key:value for dict")); compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting key:value for dict"));
@ -2637,7 +2629,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
EMIT(store_map); EMIT(store_map);
} else { } else {
if (is_key_value) { if (is_key_value) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax")); compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
#else #else
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting just a value for set")); compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting just a value for set"));
@ -2799,7 +2791,6 @@ STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pn
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("'await' outside function")); compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("'await' outside function"));
return; return;
} }
compile_require_async_context(comp, pns);
compile_atom_expr_normal(comp, pns); compile_atom_expr_normal(comp, pns);
// If it's an awaitable thing, need to reach for the __await__ method for the coroutine. // If it's an awaitable thing, need to reach for the __await__ method for the coroutine.

View File

@ -81,6 +81,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
#define mp_type_type (*mp_fun_table.type_type) #define mp_type_type (*mp_fun_table.type_type)
#define mp_type_str (*mp_fun_table.type_str) #define mp_type_str (*mp_fun_table.type_str)
#define mp_type_tuple (*((mp_obj_base_t *)mp_const_empty_tuple)->type)
#define mp_type_list (*mp_fun_table.type_list) #define mp_type_list (*mp_fun_table.type_list)
#define mp_type_EOFError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError))) #define mp_type_EOFError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))
#define mp_type_IndexError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError))) #define mp_type_IndexError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))
@ -121,6 +122,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
#define mp_obj_len(o) (mp_obj_len_dyn(o)) #define mp_obj_len(o) (mp_obj_len_dyn(o))
#define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val))) #define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val)))
#define mp_obj_get_array(o, len, items) (mp_obj_get_array_dyn((o), (len), (items)))
#define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item))) #define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item)))
#define mp_obj_assert_native_inited(o) (mp_fun_table.assert_native_inited((o))) #define mp_obj_assert_native_inited(o) (mp_fun_table.assert_native_inited((o)))
@ -264,4 +266,23 @@ static inline void mp_raise_OSError_dyn(int er) {
#define mp_obj_get_float(o) (mp_obj_get_float_to_d((o))) #define mp_obj_get_float(o) (mp_obj_get_float_to_d((o)))
#endif #endif
/******************************************************************************/
// Inline function definitions.
// *items may point inside a GC block
static inline void mp_obj_get_array_dyn(mp_obj_t o, size_t *len, mp_obj_t **items) {
const mp_obj_type_t *type = mp_obj_get_type(o);
if (type == &mp_type_tuple) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(o);
*len = t->len;
*items = &t->items[0];
} else if (type == &mp_type_list) {
mp_obj_list_t *l = MP_OBJ_TO_PTR(o);
*len = l->len;
*items = l->items;
} else {
mp_raise_TypeError("expected tuple/list");
}
}
#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H #endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H

View File

@ -108,6 +108,31 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM); assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
// Some architectures require flushing/invalidation of the I/D caches,
// so that the generated native code which was created in data RAM will
// be available for execution from instruction RAM.
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
#if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1
// Flush D-cache, so the code emitted is stored in RAM.
MP_HAL_CLEAN_DCACHE(fun_data, fun_len);
// Invalidate I-cache, so the newly-created code is reloaded from RAM.
SCB_InvalidateICache();
#endif
#elif MICROPY_EMIT_ARM
#if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
__builtin___clear_cache(fun_data, (uint8_t *)fun_data + fun_len);
#elif defined(__arm__)
// Flush I-cache and D-cache.
asm volatile (
"0:"
"mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
"bne 0b\n"
"mov r0, #0\n"
"mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
: : : "r0", "cc");
#endif
#endif
rc->kind = kind; rc->kind = kind;
rc->scope_flags = scope_flags; rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args; rc->n_pos_args = n_pos_args;

View File

@ -1797,7 +1797,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
int reg_index = REG_ARG_2; int reg_index = REG_ARG_2;
int reg_value = REG_ARG_3; int reg_value = REG_ARG_3;
emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_value); emit_pre_pop_reg_flexible(emit, &vtype_base, &reg_base, reg_index, reg_value);
#if N_X86 #if N_X64 || N_X86
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
emit_pre_pop_reg(emit, &vtype_value, reg_value); emit_pre_pop_reg(emit, &vtype_value, reg_value);
#else #else
@ -1884,7 +1884,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
EMIT_NATIVE_VIPER_TYPE_ERROR(emit, EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index)); MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index));
} }
#if N_X86 #if N_X64 || N_X86
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX) // special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
emit_pre_pop_reg(emit, &vtype_value, reg_value); emit_pre_pop_reg(emit, &vtype_value, reg_value);
#else #else

61
py/gc.c
View File

@ -167,7 +167,7 @@ void gc_init(void *start, void *end) {
MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void *)PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB)); MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void *)PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB));
// unlock the GC // unlock the GC
MP_STATE_MEM(gc_lock_depth) = 0; MP_STATE_THREAD(gc_lock_depth) = 0;
// allow auto collection // allow auto collection
MP_STATE_MEM(gc_auto_collect_enabled) = true; MP_STATE_MEM(gc_auto_collect_enabled) = true;
@ -200,19 +200,20 @@ void gc_deinit(void) {
} }
void gc_lock(void) { void gc_lock(void) {
GC_ENTER(); // This does not need to be atomic or have the GC mutex because:
MP_STATE_MEM(gc_lock_depth)++; // - each thread has its own gc_lock_depth so there are no races between threads;
GC_EXIT(); // - a hard interrupt will only change gc_lock_depth during its execution, and
// upon return will restore the value of gc_lock_depth.
MP_STATE_THREAD(gc_lock_depth)++;
} }
void gc_unlock(void) { void gc_unlock(void) {
GC_ENTER(); // This does not need to be atomic, See comment above in gc_lock.
MP_STATE_MEM(gc_lock_depth)--; MP_STATE_THREAD(gc_lock_depth)--;
GC_EXIT();
} }
bool gc_is_locked(void) { bool gc_is_locked(void) {
return MP_STATE_MEM(gc_lock_depth) != 0; return MP_STATE_THREAD(gc_lock_depth) != 0;
} }
#ifndef TRACE_MARK #ifndef TRACE_MARK
@ -356,7 +357,7 @@ STATIC void gc_mark(void *ptr) {
void gc_collect_start(void) { void gc_collect_start(void) {
GC_ENTER(); GC_ENTER();
MP_STATE_MEM(gc_lock_depth)++; MP_STATE_THREAD(gc_lock_depth)++;
#if MICROPY_GC_ALLOC_THRESHOLD #if MICROPY_GC_ALLOC_THRESHOLD
MP_STATE_MEM(gc_alloc_amount) = 0; MP_STATE_MEM(gc_alloc_amount) = 0;
#endif #endif
@ -383,9 +384,19 @@ void gc_collect_ptr(void *ptr) {
gc_mark(ptr); gc_mark(ptr);
} }
// Address sanitizer needs to know that the access to ptrs[i] must always be
// considered OK, even if it's a load from an address that would normally be
// prohibited (due to being undefined, in a red zone, etc).
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
__attribute__((no_sanitize_address))
#endif
static void *gc_get_ptr(void **ptrs, int i) {
return ptrs[i];
}
void gc_collect_root(void **ptrs, size_t len) { void gc_collect_root(void **ptrs, size_t len) {
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
void *ptr = ptrs[i]; void *ptr = gc_get_ptr(ptrs, i);
gc_mark(ptr); gc_mark(ptr);
} }
} }
@ -397,13 +408,13 @@ void gc_collect_end(void) {
MP_STATE_MEM(gc_first_free_atb_index)[i] = 0; MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
} }
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1; MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
MP_STATE_MEM(gc_lock_depth)--; MP_STATE_THREAD(gc_lock_depth)--;
GC_EXIT(); GC_EXIT();
} }
void gc_sweep_all(void) { void gc_sweep_all(void) {
GC_ENTER(); GC_ENTER();
MP_STATE_MEM(gc_lock_depth)++; MP_STATE_THREAD(gc_lock_depth)++;
MP_STATE_MEM(gc_stack_overflow) = 0; MP_STATE_MEM(gc_stack_overflow) = 0;
gc_collect_end(); gc_collect_end();
} }
@ -488,18 +499,17 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags, bool long_lived) {
return NULL; return NULL;
} }
// check if GC is locked
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
return NULL;
}
if (MP_STATE_MEM(gc_pool_start) == 0) { if (MP_STATE_MEM(gc_pool_start) == 0) {
reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM); reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
} }
GC_ENTER(); GC_ENTER();
// check if GC is locked
if (MP_STATE_MEM(gc_lock_depth) > 0) {
GC_EXIT();
return NULL;
}
size_t found_block = 0xffffffff; size_t found_block = 0xffffffff;
size_t end_block; size_t end_block;
size_t start_block; size_t start_block;
@ -676,13 +686,13 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
// force the freeing of a piece of memory // force the freeing of a piece of memory
// TODO: freeing here does not call finaliser // TODO: freeing here does not call finaliser
void gc_free(void *ptr) { void gc_free(void *ptr) {
GC_ENTER(); if (MP_STATE_THREAD(gc_lock_depth) > 0) {
if (MP_STATE_MEM(gc_lock_depth) > 0) {
// TODO how to deal with this error? // TODO how to deal with this error?
GC_EXIT();
return; return;
} }
GC_ENTER();
DEBUG_printf("gc_free(%p)\n", ptr); DEBUG_printf("gc_free(%p)\n", ptr);
if (ptr == NULL) { if (ptr == NULL) {
@ -837,15 +847,14 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
return NULL; return NULL;
} }
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
return NULL;
}
void *ptr = ptr_in; void *ptr = ptr_in;
GC_ENTER(); GC_ENTER();
if (MP_STATE_MEM(gc_lock_depth) > 0) {
GC_EXIT();
return NULL;
}
// get the GC block number corresponding to this pointer // get the GC block number corresponding to this pointer
assert(VERIFY_PTR(ptr)); assert(VERIFY_PTR(ptr));
size_t block = BLOCK_FROM_PTR(ptr); size_t block = BLOCK_FROM_PTR(ptr);

View File

@ -20,6 +20,7 @@ ifeq ("$(origin V)", "command line")
BUILD_VERBOSE=$(V) BUILD_VERBOSE=$(V)
endif endif
ifndef BUILD_VERBOSE ifndef BUILD_VERBOSE
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
BUILD_VERBOSE = 0 BUILD_VERBOSE = 0
endif endif
ifeq ($(BUILD_VERBOSE),0) ifeq ($(BUILD_VERBOSE),0)
@ -32,10 +33,6 @@ else
Q = Q =
STEPECHO = @echo STEPECHO = @echo
endif endif
# Since this is a new feature, advertise it
ifeq ($(BUILD_VERBOSE),0)
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
endif
# default settings; can be overridden in main Makefile # default settings; can be overridden in main Makefile

View File

@ -125,9 +125,13 @@ if(MICROPY_FROZEN_MANIFEST)
MICROPY_MODULE_FROZEN_MPY=\(1\) MICROPY_MODULE_FROZEN_MPY=\(1\)
) )
if(NOT MICROPY_LIB_DIR)
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)
endif()
add_custom_command( add_custom_command(
OUTPUT ${MICROPY_FROZEN_CONTENT} OUTPUT ${MICROPY_FROZEN_CONTENT}
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST} COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
DEPENDS MICROPY_FORCE_BUILD DEPENDS MICROPY_FORCE_BUILD
${MICROPY_QSTRDEFS_GENERATED} ${MICROPY_QSTRDEFS_GENERATED}
VERBATIM VERBATIM

View File

@ -374,7 +374,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
} }
} }
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("ord expects a character")); mp_raise_TypeError(MP_ERROR_TEXT("ord expects a character"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(

View File

@ -132,13 +132,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_he
STATIC mp_obj_t mp_micropython_heap_unlock(void) { STATIC mp_obj_t mp_micropython_heap_unlock(void) {
gc_unlock(); gc_unlock();
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth)); return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock);
#if MICROPY_PY_MICROPYTHON_HEAP_LOCKED #if MICROPY_PY_MICROPYTHON_HEAP_LOCKED
STATIC mp_obj_t mp_micropython_heap_locked(void) { STATIC mp_obj_t mp_micropython_heap_locked(void) {
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth)); return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked); STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked);
#endif #endif

View File

@ -173,6 +173,9 @@ STATIC void *thread_entry(void *args_in) {
mp_pystack_init(mini_pystack, &mini_pystack[128]); mp_pystack_init(mini_pystack, &mini_pystack[128]);
#endif #endif
// The GC starts off unlocked on this thread.
ts.gc_lock_depth = 0;
// set locals and globals from the calling context // set locals and globals from the calling context
mp_locals_set(args->dict_locals); mp_locals_set(args->dict_locals);
mp_globals_set(args->dict_globals); mp_globals_set(args->dict_globals);

View File

@ -570,6 +570,12 @@
#define MICROPY_VM_HOOK_RETURN #define MICROPY_VM_HOOK_RETURN
#endif #endif
// Hook for mp_sched_schedule when a function gets scheduled on sched_queue
// (this macro executes within an atomic section)
#ifndef MICROPY_SCHED_HOOK_SCHEDULED
#define MICROPY_SCHED_HOOK_SCHEDULED
#endif
// Whether to include the garbage collector // Whether to include the garbage collector
#ifndef MICROPY_ENABLE_GC #ifndef MICROPY_ENABLE_GC
#define MICROPY_ENABLE_GC (0) #define MICROPY_ENABLE_GC (0)
@ -692,6 +698,8 @@ typedef long long mp_longint_impl_t;
#define MICROPY_ENABLE_DOC_STRING (0) #define MICROPY_ENABLE_DOC_STRING (0)
#endif #endif
// Exception messages are removed (requires disabling MICROPY_ROM_TEXT_COMPRESSION)
#define MICROPY_ERROR_REPORTING_NONE (0)
// Exception messages are short static strings // Exception messages are short static strings
#define MICROPY_ERROR_REPORTING_TERSE (1) #define MICROPY_ERROR_REPORTING_TERSE (1)
// Exception messages provide basic error details // Exception messages provide basic error details
@ -1518,8 +1526,12 @@ typedef double mp_float_t;
/*****************************************************************************/ /*****************************************************************************/
/* Hooks for a port to wrap functions with attributes */ /* Hooks for a port to wrap functions with attributes */
#ifndef MICROPY_WRAP_MP_KEYBOARD_INTERRUPT #ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f #define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
#endif
#ifndef MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT
#define MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(f) f
#endif #endif
#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE #ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE

View File

@ -82,7 +82,6 @@ typedef struct _mp_state_mem_t {
int gc_stack_overflow; int gc_stack_overflow;
MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE]; MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
uint16_t gc_lock_depth;
// This variable controls auto garbage collection. If set to false then the // This variable controls auto garbage collection. If set to false then the
// GC won't automatically run when gc_alloc can't find enough blocks. But // GC won't automatically run when gc_alloc can't find enough blocks. But
@ -253,6 +252,9 @@ typedef struct _mp_state_thread_t {
uint8_t *pystack_cur; uint8_t *pystack_cur;
#endif #endif
// Locking of the GC is done per thread.
uint16_t gc_lock_depth;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// START ROOT POINTER SECTION // START ROOT POINTER SECTION
// Everything that needs GC scanning must start here, and // Everything that needs GC scanning must start here, and

View File

@ -58,7 +58,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
#else #else
__asm volatile ( __asm volatile (
#if defined(__APPLE__) || defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
"pop %rbp \n" // undo function's prelude "pop %rbp \n" // undo function's prelude
#endif #endif
"movq (%rsp), %rax \n" // load return %rip "movq (%rsp), %rax \n" // load return %rip
@ -70,7 +70,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
"movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf "movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf
"movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf "movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf
"movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf "movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf
#if defined(__APPLE__) || defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
"jmp _nlr_push_tail \n" // do the rest in C "jmp _nlr_push_tail \n" // do the rest in C
#else #else
"jmp nlr_push_tail \n" // do the rest in C "jmp nlr_push_tail \n" // do the rest in C

View File

@ -391,7 +391,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
mp_float_t val; mp_float_t val;
if (!mp_obj_get_float_maybe(arg, &val)) { if (!mp_obj_get_float_maybe(arg, &val)) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert to %q"), MP_QSTR_float); mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert to %q"), MP_QSTR_float);
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -431,7 +431,7 @@ bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag)
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
if (!mp_obj_get_complex_maybe(arg, real, imag)) { if (!mp_obj_get_complex_maybe(arg, real, imag)) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex")); mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -449,7 +449,7 @@ void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
} else if (mp_obj_is_type(o, &mp_type_list)) { } else if (mp_obj_is_type(o, &mp_type_list)) {
mp_obj_list_get(o, len, items); mp_obj_list_get(o, len, items);
} else { } else {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list")); mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -463,7 +463,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
size_t seq_len; size_t seq_len;
mp_obj_get_array(o, &seq_len, items); mp_obj_get_array(o, &seq_len, items);
if (seq_len != len) { if (seq_len != len) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length")); mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
#else #else
mp_raise_ValueError_varg( mp_raise_ValueError_varg(
@ -478,7 +478,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
if (mp_obj_is_small_int(index)) { if (mp_obj_is_small_int(index)) {
i = MP_OBJ_SMALL_INT_VALUE(index); i = MP_OBJ_SMALL_INT_VALUE(index);
} else if (!mp_obj_get_int_maybe(index, &i)) { } else if (!mp_obj_get_int_maybe(index, &i)) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers")); mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -498,7 +498,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
} }
} else { } else {
if (i < 0 || (mp_uint_t)i >= len) { if (i < 0 || (mp_uint_t)i >= len) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_IndexError(MP_ERROR_TEXT("index out of range")); mp_raise_IndexError(MP_ERROR_TEXT("index out of range"));
#else #else
mp_raise_msg_varg(&mp_type_IndexError, mp_raise_msg_varg(&mp_type_IndexError,
@ -533,7 +533,7 @@ mp_obj_t mp_obj_id(mp_obj_t o_in) {
mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t mp_obj_len(mp_obj_t o_in) {
mp_obj_t len = mp_obj_len_maybe(o_in); mp_obj_t len = mp_obj_len_maybe(o_in);
if (len == MP_OBJ_NULL) { if (len == MP_OBJ_NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object has no len")); mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -575,21 +575,21 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
} }
} }
if (value == MP_OBJ_NULL) { if (value == MP_OBJ_NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion")); mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base)); MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
#endif #endif
} else if (value == MP_OBJ_SENTINEL) { } else if (value == MP_OBJ_SENTINEL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable")); mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base)); MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
#endif #endif
} else { } else {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment")); mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(

View File

@ -792,8 +792,13 @@ extern uint64_t float_to_uint64(float f);
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type); mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args); mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
#define mp_obj_new_exception_msg(exc_type, msg) mp_obj_new_exception(exc_type)
#define mp_obj_new_exception_msg_varg(exc_type, ...) mp_obj_new_exception(exc_type)
#else
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg); mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
#endif
#ifdef va_start #ifdef va_start
mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list ap); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!) mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list ap); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
#endif #endif

View File

@ -211,11 +211,7 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args,
mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) { mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
mp_obj_array_t *self = m_new_obj(mp_obj_array_t); mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
self->base.type = &mp_type_memoryview; mp_obj_memoryview_init(self, typecode, 0, nitems, items);
self->typecode = typecode;
self->memview_offset = 0;
self->len = nitems;
self->items = items;
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }
@ -234,6 +230,14 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args,
bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL), bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),
bufinfo.buf)); bufinfo.buf));
// If the input object is a memoryview then need to point the items of the
// new memoryview to the start of the buffer so the GC can trace it.
if (mp_obj_get_type(args[0]) == &mp_type_memoryview) {
mp_obj_array_t *other = MP_OBJ_TO_PTR(args[0]);
self->memview_offset = other->memview_offset;
self->items = other->items;
}
// test if the object can be written to // test if the object can be written to
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
@ -288,6 +292,17 @@ STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
} }
} }
STATIC int typecode_for_comparison(int typecode, bool *is_unsigned) {
if (typecode == BYTEARRAY_TYPECODE) {
typecode = 'B';
}
if (typecode <= 'Z') {
typecode += 32; // to lowercase
*is_unsigned = true;
}
return typecode;
}
STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in); mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
switch (op) { switch (op) {
@ -376,15 +391,34 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
return mp_const_false; return mp_const_false;
} }
case MP_BINARY_OP_EQUAL: { case MP_BINARY_OP_EQUAL:
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL: {
mp_buffer_info_t lhs_bufinfo; mp_buffer_info_t lhs_bufinfo;
mp_buffer_info_t rhs_bufinfo; mp_buffer_info_t rhs_bufinfo;
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ); array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) { if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
return mp_const_false; return mp_const_false;
} }
// mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
// The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
// just check if the typecodes are compatible; for testing equality the types should have the
// same code except for signedness, and not be floating point because nan never equals nan.
// For > and < the types should be the same and unsigned.
// Note that typecode_for_comparison always returns lowercase letters to save code size.
// No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
bool is_unsigned = false;
const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_unsigned);
const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_unsigned);
if (lhs_code == rhs_code && lhs_code != 'f' && lhs_code != 'd' && (op == MP_BINARY_OP_EQUAL || is_unsigned)) {
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len)); return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
} }
// mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
// for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
mp_raise_NotImplementedError(NULL);
}
default: default:
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported

View File

@ -367,9 +367,11 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args,
return exc_type->make_new(exc_type, n_args, args, NULL); return exc_type->make_new(exc_type, n_args, args, NULL);
} }
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_NONE
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) { mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
return mp_obj_new_exception_msg_varg(exc_type, msg); return mp_obj_new_exception_msg_varg(exc_type, msg);
} }
#endif
// The following struct and function implement a simple printer that conservatively // The following struct and function implement a simple printer that conservatively
// allocates memory and truncates the output data if no more memory can be obtained. // allocates memory and truncates the output data if no more memory can be obtained.

View File

@ -108,7 +108,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
n_kw = kw_args->used; n_kw = kw_args->used;
} }
if (n_args + n_kw != num_fields) { if (n_args + n_kw != num_fields) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -134,7 +134,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
qstr kw = mp_obj_str_get_qstr(kw_args->table[i].key); qstr kw = mp_obj_str_get_qstr(kw_args->table[i].key);
size_t id = mp_obj_namedtuple_find_field(type, kw); size_t id = mp_obj_namedtuple_find_field(type, kw);
if (id == (size_t)-1) { if (id == (size_t)-1) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -142,7 +142,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
#endif #endif
} }
if (tuple->items[id] != MP_OBJ_NULL) { if (tuple->items[id] != MP_OBJ_NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_arg_error_terse_mismatch(); mp_arg_error_terse_mismatch();
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(

View File

@ -968,7 +968,7 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) {
} }
#endif #endif
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
STATIC NORETURN void terse_str_format_value_error(void) { STATIC NORETURN void terse_str_format_value_error(void) {
mp_raise_ValueError(MP_ERROR_TEXT("bad format string")); mp_raise_ValueError(MP_ERROR_TEXT("bad format string"));
} }
@ -989,7 +989,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
vstr_add_byte(&vstr, '}'); vstr_add_byte(&vstr, '}');
continue; continue;
} }
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("single '}' encountered in format string")); mp_raise_ValueError(MP_ERROR_TEXT("single '}' encountered in format string"));
@ -1028,7 +1028,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
if (str < top && (*str == 'r' || *str == 's')) { if (str < top && (*str == 'r' || *str == 's')) {
conversion = *str++; conversion = *str++;
} else { } else {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
mp_raise_ValueError(MP_ERROR_TEXT("bad conversion specifier")); mp_raise_ValueError(MP_ERROR_TEXT("bad conversion specifier"));
@ -1066,14 +1066,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
} }
} }
if (str >= top) { if (str >= top) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("unmatched '{' in format")); mp_raise_ValueError(MP_ERROR_TEXT("unmatched '{' in format"));
#endif #endif
} }
if (*str != '}') { if (*str != '}') {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("expected ':' after format specifier")); mp_raise_ValueError(MP_ERROR_TEXT("expected ':' after format specifier"));
@ -1086,7 +1086,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
int index = 0; int index = 0;
if (MP_LIKELY(unichar_isdigit(*field_name))) { if (MP_LIKELY(unichar_isdigit(*field_name))) {
if (*arg_i > 0) { if (*arg_i > 0) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError( mp_raise_ValueError(
@ -1116,7 +1116,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
} }
} else { } else {
if (*arg_i < 0) { if (*arg_i < 0) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError( mp_raise_ValueError(
@ -1209,7 +1209,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
type = *s++; type = *s++;
} }
if (*s) { if (*s) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("invalid format specifier")); mp_raise_ValueError(MP_ERROR_TEXT("invalid format specifier"));
@ -1230,14 +1230,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) { if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) {
if (type == 's') { if (type == 's') {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("sign not allowed in string format specifier")); mp_raise_ValueError(MP_ERROR_TEXT("sign not allowed in string format specifier"));
#endif #endif
} }
if (type == 'c') { if (type == 'c') {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError( mp_raise_ValueError(
@ -1301,7 +1301,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
break; break;
default: default:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError_varg( mp_raise_ValueError_varg(
@ -1373,7 +1373,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
#endif #endif
default: default:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError_varg( mp_raise_ValueError_varg(
@ -1385,7 +1385,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
// arg doesn't look like a number // arg doesn't look like a number
if (align == '=') { if (align == '=') {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError( mp_raise_ValueError(
@ -1409,7 +1409,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
} }
default: default:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError_varg( mp_raise_ValueError_varg(
@ -1438,7 +1438,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
mp_check_self(mp_obj_is_str_or_bytes(pattern)); mp_check_self(mp_obj_is_str_or_bytes(pattern));
GET_STR_DATA_LEN(pattern, str, len); GET_STR_DATA_LEN(pattern, str, len);
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_TERSE
const byte *start_str = str; const byte *start_str = str;
#endif #endif
bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes); bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes);
@ -1470,7 +1470,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
const byte *key = ++str; const byte *key = ++str;
while (*str != ')') { while (*str != ')') {
if (str >= top) { if (str >= top) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format key")); mp_raise_ValueError(MP_ERROR_TEXT("incomplete format key"));
@ -1534,7 +1534,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
if (str >= top) { if (str >= top) {
incomplete_format: incomplete_format:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format")); mp_raise_ValueError(MP_ERROR_TEXT("incomplete format"));
@ -1620,7 +1620,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
break; break;
default: default:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
terse_str_format_value_error(); terse_str_format_value_error();
#else #else
mp_raise_ValueError_varg( mp_raise_ValueError_varg(
@ -2165,7 +2165,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
} }
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) { STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly")); mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly"));
#else #else
const qstr src_name = mp_obj_get_type_qstr(self_in); const qstr src_name = mp_obj_get_type_qstr(self_in);

View File

@ -373,7 +373,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, cons
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw); m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
} }
if (init_ret != mp_const_none) { if (init_ret != mp_const_none) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("__init__() should return None")); mp_raise_TypeError(MP_ERROR_TEXT("__init__() should return None"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("__init__() should return None, not '%q'"), mp_raise_TypeError_varg(MP_ERROR_TEXT("__init__() should return None, not '%q'"),
@ -889,7 +889,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL}; mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
mp_obj_t call = mp_obj_instance_get_call(self_in, member); mp_obj_t call = mp_obj_instance_get_call(self_in, member);
if (call == MP_OBJ_NULL) { if (call == MP_OBJ_NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object not callable")); mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"),
@ -1029,7 +1029,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
if (self->make_new == NULL) { if (self->make_new == NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance")); mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("cannot create '%q' instances"), self->name); mp_raise_TypeError_varg(MP_ERROR_TEXT("cannot create '%q' instances"), self->name);
@ -1171,7 +1171,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]); mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
// TODO: Verify with CPy, tested on function type // TODO: Verify with CPy, tested on function type
if (t->make_new == NULL) { if (t->make_new == NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("type is not an acceptable base type")); mp_raise_TypeError(MP_ERROR_TEXT("type is not an acceptable base type"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(

View File

@ -147,7 +147,7 @@ overflow:
value_error: value_error:
{ {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError, mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError,
MP_ERROR_TEXT("invalid syntax for integer")); MP_ERROR_TEXT("invalid syntax for integer"));
raise_exc(exc, lex); raise_exc(exc, lex);

View File

@ -298,9 +298,7 @@ STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t
mp_prof_is_executing = false; mp_prof_is_executing = false;
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception); mp_handle_pending(true);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
} }
return top; return top;
} }

View File

@ -167,13 +167,13 @@ STATIC const char *find_completions(const char *s_start, size_t s_len,
for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) { for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
size_t d_len; size_t d_len;
const char *d_str = (const char *)qstr_data(q, &d_len); const char *d_str = (const char *)qstr_data(q, &d_len);
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
if (test_qstr(obj, q)) {
// special case; filter out words that begin with underscore // special case; filter out words that begin with underscore
// unless there's already a partial match // unless there's already a partial match
if (s_len == 0 && d_str[0] == '_') { if (s_len == 0 && d_str[0] == '_') {
continue; continue;
} }
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
if (test_qstr(obj, q)) {
if (match_str == NULL) { if (match_str == NULL) {
match_str = d_str; match_str = d_str;
*match_len = d_len; *match_len = d_len;
@ -297,7 +297,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
if (q_first == 0) { if (q_first == 0) {
// If there're no better alternatives, and if it's first word // If there're no better alternatives, and if it's first word
// in the line, try to complete "import". // in the line, try to complete "import".
if (s_start == org_str && s_len > 0) { if (s_start == org_str && s_len > 0 && s_len < sizeof(import_str) - 1) {
if (memcmp(s_start, import_str, s_len) == 0) { if (memcmp(s_start, import_str, s_len) == 0) {
*compl_str = import_str + s_len; *compl_str = import_str + s_len;
return sizeof(import_str) - 1 - s_len; return sizeof(import_str) - 1 - s_len;

View File

@ -159,9 +159,6 @@ void mp_deinit(void) {
#ifdef MICROPY_PORT_DEINIT_FUNC #ifdef MICROPY_PORT_DEINIT_FUNC
MICROPY_PORT_DEINIT_FUNC; MICROPY_PORT_DEINIT_FUNC;
#endif #endif
// mp_obj_dict_free(&dict_main);
// mp_map_deinit(&MP_STATE_VM(mp_loaded_modules_map));
} }
mp_obj_t mp_load_name(qstr qst) { mp_obj_t mp_load_name(qstr qst) {
@ -193,7 +190,7 @@ mp_obj_t mp_load_global(qstr qst) {
#endif #endif
elem = mp_map_lookup((mp_map_t *)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); elem = mp_map_lookup((mp_map_t *)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
if (elem == NULL) { if (elem == NULL) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_msg(&mp_type_NameError, MP_ERROR_TEXT("name not defined")); mp_raise_msg(&mp_type_NameError, MP_ERROR_TEXT("name not defined"));
#else #else
mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT("name '%q' is not defined"), qst); mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT("name '%q' is not defined"), qst);
@ -293,20 +290,20 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
} }
// With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int(). // With MP_UNARY_OP_INT, mp_unary_op() becomes a fallback for mp_obj_get_int().
// In this case provide a more focused error message to not confuse, e.g. chr(1.0) // In this case provide a more focused error message to not confuse, e.g. chr(1.0)
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
if (op == MP_UNARY_OP_INT) { if (op == MP_UNARY_OP_INT) {
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int")); mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int"));
} else { } else {
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator")); mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
} }
} else { #else
if (op == MP_UNARY_OP_INT) { if (op == MP_UNARY_OP_INT) {
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to int"), mp_obj_get_type_qstr(arg)); mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert %q to int"), mp_obj_get_type_qstr(arg));
} else { } else {
mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported type for %q: '%q'"), mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported type for %q: '%q'"),
mp_unary_op_method_name[op], mp_obj_get_type_qstr(arg)); mp_unary_op_method_name[op], mp_obj_get_type_qstr(arg));
} }
} #endif
} }
} }
@ -612,7 +609,7 @@ generic_binary_op:
} }
unsupported_op: unsupported_op:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator")); mp_raise_TypeError(MP_ERROR_TEXT("unsupported type for operator"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -654,7 +651,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons
return type->call(fun_in, n_args, n_kw, args); return type->call(fun_in, n_args, n_kw, args);
} }
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object not callable")); mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_obj_get_type_qstr(fun_in)); mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_obj_get_type_qstr(fun_in));
@ -882,14 +879,14 @@ void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) {
return; return;
too_short: too_short:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack")); mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
#else #else
mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"), mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"),
(int)seq_len); (int)seq_len);
#endif #endif
too_long: too_long:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack")); mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
#else #else
mp_raise_ValueError_varg(MP_ERROR_TEXT("too many values to unpack (expected %d)"), mp_raise_ValueError_varg(MP_ERROR_TEXT("too many values to unpack (expected %d)"),
@ -951,7 +948,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) {
return; return;
too_short: too_short:
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack")); mp_raise_ValueError(MP_ERROR_TEXT("wrong number of values to unpack"));
#else #else
mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"), mp_raise_ValueError_varg(MP_ERROR_TEXT("need more than %d values to unpack"),
@ -1138,7 +1135,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
if (dest[0] == MP_OBJ_NULL) { if (dest[0] == MP_OBJ_NULL) {
// no attribute/method called attr // no attribute/method called attr
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute")); mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute"));
#else #else
// following CPython, we give a more detailed error message for type objects // following CPython, we give a more detailed error message for type objects
@ -1212,7 +1209,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
} }
#endif #endif
} }
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute")); mp_raise_AttributeError(MP_ERROR_TEXT("no such attribute"));
#else #else
mp_raise_msg_varg(&mp_type_AttributeError, mp_raise_msg_varg(&mp_type_AttributeError,
@ -1257,7 +1254,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
} }
// object not iterable // object not iterable
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object not iterable")); mp_raise_TypeError(MP_ERROR_TEXT("object not iterable"));
#else #else
mp_raise_TypeError_varg( mp_raise_TypeError_varg(
@ -1279,7 +1276,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) {
// __next__ exists, call it and return its result // __next__ exists, call it and return its result
return mp_call_method_n_kw(0, 0, dest); return mp_call_method_n_kw(0, 0, dest);
} else { } else {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator")); mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"), mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"),
@ -1315,7 +1312,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) {
} }
} }
} else { } else {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator")); mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator"));
#else #else
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"), mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"),
@ -1565,6 +1562,26 @@ NORETURN void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
nlr_raise(mp_obj_new_exception_arg1(exc_type, arg)); nlr_raise(mp_obj_new_exception_arg1(exc_type, arg));
} }
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
NORETURN void mp_raise_type(const mp_obj_type_t *exc_type) {
nlr_raise(mp_obj_new_exception(exc_type));
}
NORETURN void mp_raise_ValueError_no_msg(void) {
mp_raise_type(&mp_type_ValueError);
}
NORETURN void mp_raise_TypeError_no_msg(void) {
mp_raise_type(&mp_type_TypeError);
}
NORETURN void mp_raise_NotImplementedError_no_msg(void) {
mp_raise_type(&mp_type_NotImplementedError);
}
#else
NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) { NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
if (msg == NULL) { if (msg == NULL) {
nlr_raise(mp_obj_new_exception(exc_type)); nlr_raise(mp_obj_new_exception(exc_type));
@ -1691,6 +1708,8 @@ NORETURN void mp_raise_MpyError(const compressed_string_t *msg) {
mp_raise_msg(&mp_type_MpyError, msg); mp_raise_msg(&mp_type_MpyError, msg);
} }
#endif
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK #if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
NORETURN void mp_raise_recursion_depth(void) { NORETURN void mp_raise_recursion_depth(void) {
mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded")); mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded"));

View File

@ -68,7 +68,8 @@ extern const byte mp_binary_op_method_name[];
void mp_init(void); void mp_init(void);
void mp_deinit(void); void mp_deinit(void);
void mp_keyboard_interrupt(void); void mp_sched_exception(mp_obj_t exc);
void mp_sched_keyboard_interrupt(void);
void mp_handle_pending(bool raise_exc); void mp_handle_pending(bool raise_exc);
void mp_handle_pending_tail(mp_uint_t atomic_state); void mp_handle_pending_tail(mp_uint_t atomic_state);
@ -162,6 +163,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level);
mp_obj_t mp_import_from(mp_obj_t module, qstr name); mp_obj_t mp_import_from(mp_obj_t module, qstr name);
void mp_import_all(mp_obj_t module); void mp_import_all(mp_obj_t module);
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
NORETURN void mp_raise_type(const mp_obj_type_t *exc_type);
NORETURN void mp_raise_ValueError_no_msg(void);
NORETURN void mp_raise_TypeError_no_msg(void);
NORETURN void mp_raise_NotImplementedError_no_msg(void);
#define mp_raise_msg(exc_type, msg) mp_raise_type(exc_type)
#define mp_raise_msg_varg(exc_type, ...) mp_raise_type(exc_type)
#define mp_raise_ValueError(msg) mp_raise_ValueError_no_msg()
#define mp_raise_TypeError(msg) mp_raise_TypeError_no_msg()
#define mp_raise_NotImplementedError(msg) mp_raise_NotImplementedError_no_msg()
#else
#define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL) #define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL)
#if !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME) #if !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME)
NORETURN void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg); NORETURN void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
@ -191,6 +203,7 @@ NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt,
NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...); NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...);
NORETURN void mp_raise_MpyError(const compressed_string_t *msg); NORETURN void mp_raise_MpyError(const compressed_string_t *msg);
NORETURN void mp_raise_recursion_depth(void); NORETURN void mp_raise_recursion_depth(void);
#endif
#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
#undef mp_check_self #undef mp_check_self

View File

@ -28,17 +28,21 @@
#include "py/runtime.h" #include "py/runtime.h"
#if MICROPY_KBD_EXCEPTION void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_exception)(mp_obj_t exc) {
// This function may be called asynchronously at any time so only do the bare minimum. MP_STATE_VM(mp_pending_exception) = exc;
void MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(mp_keyboard_interrupt)(void) {
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
#if MICROPY_ENABLE_SCHEDULER #if MICROPY_ENABLE_SCHEDULER
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING; MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
} }
#endif #endif
} }
#if MICROPY_KBD_EXCEPTION
// This function may be called asynchronously at any time so only do the bare minimum.
void MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(mp_sched_keyboard_interrupt)(void) {
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
mp_sched_exception(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
}
#endif #endif
#if MICROPY_ENABLE_SCHEDULER #if MICROPY_ENABLE_SCHEDULER
@ -130,6 +134,7 @@ bool MICROPY_WRAP_MP_SCHED_SCHEDULE(mp_sched_schedule)(mp_obj_t function, mp_obj
uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++); uint8_t iput = IDX_MASK(MP_STATE_VM(sched_idx) + MP_STATE_VM(sched_len)++);
MP_STATE_VM(sched_queue)[iput].func = function; MP_STATE_VM(sched_queue)[iput].func = function;
MP_STATE_VM(sched_queue)[iput].arg = arg; MP_STATE_VM(sched_queue)[iput].arg = arg;
MICROPY_SCHED_HOOK_SCHEDULED;
ret = true; ret = true;
} else { } else {
// schedule queue is full // schedule queue is full

View File

@ -40,7 +40,7 @@ void mp_stack_check(void);
#else #else
#define mp_stack_set_limit(limit) #define mp_stack_set_limit(limit) (void)(limit)
#define MP_STACK_CHECK() #define MP_STACK_CHECK()
#endif #endif

View File

@ -293,7 +293,7 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
// Compare mp_interrupt_char with wanted_char and ignore if not matched // Compare mp_interrupt_char with wanted_char and ignore if not matched
if (mp_interrupt_char == wanted_char) { if (mp_interrupt_char == wanted_char) {
tud_cdc_n_read_flush(itf); // flush read fifo tud_cdc_n_read_flush(itf); // flush read fifo
mp_keyboard_interrupt(); mp_sched_keyboard_interrupt();
} }
} }

View File

@ -41,14 +41,23 @@ except ValueError:
# equality (CPython requires both sides are array) # equality (CPython requires both sides are array)
print(bytes(array.array('b', [0x61, 0x62, 0x63])) == b'abc') print(bytes(array.array('b', [0x61, 0x62, 0x63])) == b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) == b'abc') print(array.array('b', [0x61, 0x62, 0x63]) == b'abc')
print(array.array('B', [0x61, 0x62, 0x63]) == b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) != b'abc') print(array.array('b', [0x61, 0x62, 0x63]) != b'abc')
print(array.array('b', [0x61, 0x62, 0x63]) == b'xyz') print(array.array('b', [0x61, 0x62, 0x63]) == b'xyz')
print(array.array('b', [0x61, 0x62, 0x63]) != b'xyz') print(array.array('b', [0x61, 0x62, 0x63]) != b'xyz')
print(b'abc' == array.array('b', [0x61, 0x62, 0x63])) print(b'abc' == array.array('b', [0x61, 0x62, 0x63]))
print(b'abc' == array.array('B', [0x61, 0x62, 0x63]))
print(b'abc' != array.array('b', [0x61, 0x62, 0x63])) print(b'abc' != array.array('b', [0x61, 0x62, 0x63]))
print(b'xyz' == array.array('b', [0x61, 0x62, 0x63])) print(b'xyz' == array.array('b', [0x61, 0x62, 0x63]))
print(b'xyz' != array.array('b', [0x61, 0x62, 0x63])) print(b'xyz' != array.array('b', [0x61, 0x62, 0x63]))
compatible_typecodes = []
for t in ["b", "h", "i", "l", "q"]:
compatible_typecodes.append((t, t))
compatible_typecodes.append((t, t.upper()))
for a, b in compatible_typecodes:
print(array.array(a, [1, 2]) == array.array(b, [1, 2]))
class X(array.array): class X(array.array):
pass pass
@ -57,3 +66,24 @@ print(X('b', [0x61, 0x62, 0x63]) == b'abc')
print(X('b', [0x61, 0x62, 0x63]) != b'abc') print(X('b', [0x61, 0x62, 0x63]) != b'abc')
print(X('b', [0x61, 0x62, 0x63]) == array.array('b', [0x61, 0x62, 0x63])) print(X('b', [0x61, 0x62, 0x63]) == array.array('b', [0x61, 0x62, 0x63]))
print(X('b', [0x61, 0x62, 0x63]) != array.array('b', [0x61, 0x62, 0x63])) print(X('b', [0x61, 0x62, 0x63]) != array.array('b', [0x61, 0x62, 0x63]))
# other comparisons
for typecode in ["B", "H", "I", "L", "Q"]:
a = array.array(typecode, [1, 1])
print(a < a)
print(a <= a)
print(a > a)
print(a >= a)
al = array.array(typecode, [1, 0])
ab = array.array(typecode, [1, 2])
print(a < al)
print(a <= al)
print(a > al)
print(a >= al)
print(a < ab)
print(a <= ab)
print(a > ab)
print(a >= ab)

View File

@ -17,3 +17,15 @@ print(a[0])
a = array.array('P') a = array.array('P')
a.append(1) a.append(1)
print(a[0]) print(a[0])
# comparison between mismatching binary layouts is not implemented
typecodes = ["b", "h", "i", "l", "q", "P", "O", "S", "f", "d"]
for a in typecodes:
for b in typecodes:
if a == b and a not in ["f", "d"]:
continue
try:
array.array(a) == array.array(b)
print('FAIL')
except NotImplementedError:
pass

View File

@ -0,0 +1,19 @@
# test syntax errors using async
try:
exec
except NameError:
print("SKIP")
raise SystemExit
def test_syntax(code):
try:
exec(code)
print("no SyntaxError")
except SyntaxError:
print("SyntaxError")
test_syntax("async for x in (): x")
test_syntax("async with x: x")

View File

@ -0,0 +1,2 @@
SyntaxError
SyntaxError

View File

@ -27,6 +27,26 @@ print(bytearray([1]) == b"1")
print(b"1" == bytearray([1])) print(b"1" == bytearray([1]))
print(bytearray() == bytearray()) print(bytearray() == bytearray())
b1 = bytearray([1, 2, 3])
b2 = bytearray([1, 2, 3])
b3 = bytearray([1, 3])
print(b1 == b2)
print(b2 != b3)
print(b1 <= b2)
print(b1 <= b3)
print(b1 < b3)
print(b1 >= b2)
print(b3 >= b2)
print(b3 > b2)
print(b1 != b2)
print(b2 == b3)
print(b1 > b2)
print(b1 > b3)
print(b1 >= b3)
print(b1 < b2)
print(b3 < b2)
print(b3 <= b2)
# comparison with other type should return False # comparison with other type should return False
print(bytearray() == 1) print(bytearray() == 1)

View File

@ -1,3 +1,5 @@
# test basic properties of exceptions
print(repr(IndexError())) print(repr(IndexError()))
print(str(IndexError())) print(str(IndexError()))
@ -12,3 +14,6 @@ s = StopIteration()
print(s.value) print(s.value)
s = StopIteration(1, 2, 3) s = StopIteration(1, 2, 3)
print(s.value) print(s.value)
print(OSError().errno)
print(OSError(1, "msg").errno)

View File

@ -1,14 +1,4 @@
print(1 is 1)
print(1 is 2)
print(1 is not 1)
print(1 is not 2)
print([1, 2] is [1, 2]) print([1, 2] is [1, 2])
a = [1, 2] a = [1, 2]
b = a b = a
print(b is a) print(b is a)
# TODO: strings require special "is" handling, postponed
# until qstr refactor.
#print("a" is "a")

View File

@ -0,0 +1,13 @@
# test "is" and "is not" with literal arguments
# these raise a SyntaxWarning in CPython because the results are
# implementation dependent; see https://bugs.python.org/issue34850
print(1 is 1)
print(1 is 2)
print(1 is not 1)
print(1 is not 2)
print("a" is "a")
print("a" is "b")
print("a" is not "a")
print("a" is not "b")

View File

@ -0,0 +1,8 @@
True
False
False
True
True
False
False
True

View File

@ -21,3 +21,13 @@ for i in range(100000):
# check that the memoryview is still what we want # check that the memoryview is still what we want
print(list(m)) print(list(m))
# check that creating a memoryview of a memoryview retains the underlying data
m = None
gc.collect() # cleanup from previous test
m = memoryview(memoryview(bytearray(i for i in range(50)))[5:-5])
print(sum(m), list(m[:10]))
gc.collect()
for i in range(10):
list(range(10)) # allocate memory to overwrite any reclaimed heap
print(sum(m), list(m[:10]))

View File

@ -29,18 +29,10 @@ except TypeError:
print('TypeError') print('TypeError')
# unsupported subscription # unsupported subscription
try:
1[0]
except TypeError:
print('TypeError')
try: try:
1[0] = 1 1[0] = 1
except TypeError: except TypeError:
print('TypeError') print('TypeError')
try:
''['']
except TypeError:
print('TypeError')
try: try:
'a'[0] = 1 'a'[0] = 1
except TypeError: except TypeError:
@ -50,12 +42,6 @@ try:
except TypeError: except TypeError:
print('TypeError') print('TypeError')
# not callable
try:
1()
except TypeError:
print('TypeError')
# not an iterator # not an iterator
try: try:
next(1) next(1)

View File

@ -0,0 +1,18 @@
# test errors from bad operations with literals
# these raise a SyntaxWarning in CPython; see https://bugs.python.org/issue15248
# unsupported subscription
try:
1[0]
except TypeError:
print("TypeError")
try:
""[""]
except TypeError:
print("TypeError")
# not callable
try:
1()
except TypeError:
print("TypeError")

View File

@ -0,0 +1,3 @@
TypeError
TypeError
TypeError

View File

@ -1,6 +1,10 @@
# test subclassing a native exception
class MyExc(Exception): class MyExc(Exception):
pass pass
e = MyExc(100, "Some error") e = MyExc(100, "Some error")
print(e) print(e)
print(repr(e)) print(repr(e))
@ -20,3 +24,19 @@ try:
raise MyExc("Some error2") raise MyExc("Some error2")
except: except:
print("Caught user exception") print("Caught user exception")
class MyStopIteration(StopIteration):
pass
print(MyStopIteration().value)
print(MyStopIteration(1).value)
class MyOSError(OSError):
pass
print(MyOSError().errno)
print(MyOSError(1, "msg").errno)

View File

@ -0,0 +1,13 @@
"""
categories: Core,Functions
description: Function objects do not have the ``__module__`` attribute
cause: MicroPython is optimized for reduced code size and RAM usage.
workaround: Use ``sys.modules[function.__globals__['__name__']]`` for non-builtin modules.
"""
def f():
pass
print(f.__module__)

View File

@ -0,0 +1,9 @@
"""
categories: Modules,array
description: Comparison between different typecodes not supported
cause: Code size
workaround: Compare individual elements
"""
import array
array.array("b", [1, 2]) == array.array("i", [1, 2])

View File

@ -0,0 +1,10 @@
"""
categories: Modules,array
description: Overflow checking is not implemented
cause: MicroPython implements implicit truncation in order to reduce code size and execution time
workaround: If CPython compatibility is needed then mask the value explicitly
"""
import array
a = array.array("b", [257])
print(a)

View File

@ -0,0 +1,12 @@
"""
categories: Modules,random
description: ``getrandbits`` method can only return a maximum of 32 bits at a time.
cause: PRNG's internal state is only 32bits so it can only return a maximum of 32 bits of data at a time.
workaround: If you need a number that has more than 32 bits then utilize the random module from micropython-lib.
"""
import random
x = random.getrandbits(64)
print("{}".format(x))

View File

@ -0,0 +1,12 @@
"""
categories: Modules,random
description: ``randint`` method can only return an integer that is at most the native word size.
cause: PRNG is only able to generate 32 bits of state at a time. The result is then cast into a native sized int instead of a full int object.
workaround: If you need integers larger than native wordsize use the random module from micropython-lib.
"""
import random
x = random.randint(2 ** 128 - 1, 2 ** 128)
print("x={}".format(x))

View File

@ -0,0 +1,9 @@
"""
categories: Types,Exception
description: All exceptions have readable ``value`` and ``errno`` attributes, not just ``StopIteration`` and ``OSError``.
cause: MicroPython is optimised to reduce code size.
workaround: Only use ``value`` on ``StopIteration`` exceptions, and ``errno`` on ``OSError`` exceptions. Do not use or rely on these attributes on other exceptions.
"""
e = Exception(1)
print(e.value)
print(e.errno)

View File

@ -0,0 +1,9 @@
"""
categories: Types,int
description: ``bit_length`` method doesn't exist.
cause: bit_length method is not implemented.
workaround: Avoid using this method on MicroPython.
"""
x = 255
print("{} is {} bits long.".format(x, x.bit_length()))

View File

@ -65,7 +65,7 @@ print(db.seq(1, b"qux"))
try: try:
db.seq(b"foo1") db.seq(b"foo1")
except OSError as e: except OSError as e:
print(e.args[0] == uerrno.EINVAL) print(e.errno == uerrno.EINVAL)
print(list(db.keys())) print(list(db.keys()))
print(list(db.values())) print(list(db.values()))

View File

@ -27,7 +27,7 @@ class Device(uio.IOBase):
try: try:
db = btree.open(Device(), pagesize=511) db = btree.open(Device(), pagesize=511)
except OSError as er: except OSError as er:
print("OSError", er.args[0] == uerrno.EINVAL) print("OSError", er.errno == uerrno.EINVAL)
# Valid pagesize, device returns error on read; errno comes from Device.readinto # Valid pagesize, device returns error on read; errno comes from Device.readinto
try: try:

View File

@ -21,3 +21,6 @@ for i in range(N):
db[b"thekey" + str(i)] = b"thelongvalue" + str(i) db[b"thekey" + str(i)] = b"thelongvalue" + str(i)
print(db[b"thekey" + str(i)]) print(db[b"thekey" + str(i)])
gc.collect() gc.collect()
# Reclaim memory allocated by the db object.
db.close()

View File

@ -1,9 +1,14 @@
try: try:
import framebuf import framebuf, usys
except ImportError: except ImportError:
print("SKIP") print("SKIP")
raise SystemExit raise SystemExit
# This test and its .exp file is based on a little-endian architecture.
if usys.byteorder != "little":
print("SKIP")
raise SystemExit
def printbuf(): def printbuf():
print("--8<--") print("--8<--")

View File

@ -1,11 +1,16 @@
# test subclassing framebuf.FrameBuffer # test subclassing framebuf.FrameBuffer
try: try:
import framebuf import framebuf, usys
except ImportError: except ImportError:
print("SKIP") print("SKIP")
raise SystemExit raise SystemExit
# This test and its .exp file is based on a little-endian architecture.
if usys.byteorder != "little":
print("SKIP")
raise SystemExit
class FB(framebuf.FrameBuffer): class FB(framebuf.FrameBuffer):
def __init__(self, n): def __init__(self, n):

View File

@ -0,0 +1,41 @@
# Test cancelling a task that is waiting on a task that just finishes.
try:
import uasyncio as asyncio
except ImportError:
try:
import asyncio
except ImportError:
print("SKIP")
raise SystemExit
async def sleep_task():
print("sleep_task sleep")
await asyncio.sleep(0)
print("sleep_task wake")
async def wait_task(t):
print("wait_task wait")
await t
print("wait_task wake")
async def main():
waiting_task = asyncio.create_task(wait_task(asyncio.create_task(sleep_task())))
print("main sleep")
await asyncio.sleep(0)
print("main sleep")
await asyncio.sleep(0)
waiting_task.cancel()
print("main wait")
try:
await waiting_task
except asyncio.CancelledError as er:
print(repr(er))
asyncio.run(main())

View File

@ -0,0 +1,7 @@
main sleep
sleep_task sleep
wait_task wait
main sleep
sleep_task wake
main wait
CancelledError()

View File

@ -22,3 +22,19 @@ print("%.4f" % S.f64)
S.uf64 = 12.34 S.uf64 = 12.34
print("%.4f" % S.uf64) print("%.4f" % S.uf64)
# array of float/double
desc = {
"af32": (uctypes.ARRAY | 0, uctypes.FLOAT32 | 2),
"af64": (uctypes.ARRAY | 0, uctypes.FLOAT64 | 2),
}
data = bytearray(16)
S = uctypes.struct(uctypes.addressof(data), desc, uctypes.LITTLE_ENDIAN)
S.af32[0] = 1
S.af32[1] = 2
print("%.4f %.4f" % (S.af32[0], S.af32[1]), data)
S.af64[0] = 1
S.af64[1] = 2
print("%.4f %.4f" % (S.af64[0], S.af64[1]), data)

View File

@ -1,3 +1,5 @@
12.3400 12.3400
12.3400 12.3400
12.3400 12.3400
1.0000 2.0000 bytearray(b'\x00\x00\x80?\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00')
1.0000 2.0000 bytearray(b'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@')

View File

@ -6,3 +6,5 @@ except ImportError:
print(uctypes.sizeof({"f": uctypes.FLOAT32})) print(uctypes.sizeof({"f": uctypes.FLOAT32}))
print(uctypes.sizeof({"f": uctypes.FLOAT64})) print(uctypes.sizeof({"f": uctypes.FLOAT64}))
print(uctypes.sizeof({"f": (uctypes.ARRAY | 0, uctypes.FLOAT32 | 2)}))
print(uctypes.sizeof({"f": (uctypes.ARRAY | 0, uctypes.FLOAT64 | 2)}))

View File

@ -1,2 +1,4 @@
4 4
8 8
8
16

View File

@ -0,0 +1,35 @@
try:
import uhashlib
except ImportError:
print("SKIP")
raise SystemExit
for algo_name in ("md5", "sha1", "sha256"):
algo = getattr(uhashlib, algo_name, None)
if not algo:
continue
# Running .digest() several times in row is not supported.
h = algo(b"123")
h.digest()
try:
h.digest()
print("fail")
except ValueError:
# Expected path, don't print anything so test output is the
# same even if the algorithm is not implemented on the port.
pass
# Partial digests are not supported.
h = algo(b"123")
h.digest()
try:
h.update(b"456")
print("fail")
except ValueError:
# Expected path, don't print anything so test output is the
# same even if the algorithm is not implemented on the port.
pass
print("done")

View File

@ -0,0 +1 @@
done

View File

@ -22,8 +22,11 @@ r = random.getrandbits(16)
random.seed(1) random.seed(1)
print(random.getrandbits(16) == r) print(random.getrandbits(16) == r)
# check that it throws an error for zero bits # check that zero bits works
print(random.getrandbits(0))
# check that it throws an error for negative bits
try: try:
random.getrandbits(0) random.getrandbits(-1)
except ValueError: except ValueError:
print("ValueError") print("ValueError")

View File

@ -0,0 +1,4 @@
True
True
0
ValueError

View File

@ -33,7 +33,7 @@ poller.unregister(s)
try: try:
poller.modify(s, select.POLLIN) poller.modify(s, select.POLLIN)
except OSError as e: except OSError as e:
assert e.args[0] == errno.ENOENT assert e.errno == errno.ENOENT
# poll after closing the socket, should return POLLNVAL # poll after closing the socket, should return POLLNVAL
poller.register(s) poller.register(s)

Some files were not shown because too many files have changed in this diff Show More