Commit Graph

3081 Commits

Author SHA1 Message Date
Damien George
136cb7f27c py/map: Don't include ordered-dict mutating code when not needed. 2017-12-19 13:37:15 +11:00
Damien George
f5fb68e94f py/runtime: Remove unnecessary break statements from switch. 2017-12-19 13:13:21 +11:00
Paul Sokolovsky
6364401666 py/objgenerator: Allow to pend an exception for next execution.
This implements .pend_throw(exc) method, which sets up an exception to be
triggered on the next call to generator's .__next__() or .send() method.
This is unlike .throw(), which immediately starts to execute the generator
to process the exception. This effectively adds Future-like capabilities
to generator protocol (exception will be raised in the future).

The need for such a method arised to implement uasyncio wait_for() function
efficiently (its behavior is clearly "Future" like, and normally would
require to introduce an expensive Future wrapper around all native
couroutines, like upstream asyncio does).

py/objgenerator: pend_throw: Return previous pended value.

This effectively allows to store an additional value (not necessary an
exception) in a coroutine while it's not being executed. uasyncio has
exactly this usecase: to mark a coro waiting in I/O queue (and thus
not executed in the normal scheduling queue), for the purpose of
implementing wait_for() function (cancellation of such waiting coro
by a timeout).
2017-12-15 20:20:36 +02:00
Damien George
cf8e8c29e7 py/emitglue: Change type of bit-field to explicitly unsigned mp_uint_t.
Some compilers can treat enum types as signed, in which case 3 bits is not
enough to encode all mp_raw_code_kind_t values.  So change the type to
mp_uint_t.
2017-12-15 10:21:10 +11:00
Damien George
f1c9e7760d py/builtinimport: Call __init__ for modules imported via a weak link.
This is a bit of a clumsy way of doing it but solves the issue of __init__
not running when a module is imported via its weak-link name.  Ideally a
better solution would be found.
2017-12-13 14:48:53 +11:00
Damien George
c78ef92d78 py/objtype: Refactor object's handling of __new__ to not create 2 objs.
Before this patch, if a user defined the __new__() function for a class
then two instances of that class would be created: once before __new__ is
called and once during the __new__ call (assuming the user creates some
instance, eg using super().__new__, which is most of the time).  The first
one was then discarded.  This refactor makes it so that a new instance is
only created if the user __new__ function doesn't exist.
2017-12-12 16:53:44 +11:00
Damien George
d32d22dfd7 py/objtype: Implement better support for overriding native's __init__.
This patch cleans up and generalises part of the code which handles
overriding and calling a native base-class's __init__ method.  It defers
the call to the native make_new() function until after the user (Python)
__init__() method has run.  That user method now has the chance to call the
native __init__/make_new and pass it different arguments.  If the user
doesn't call the super().__init__ method then it will be called
automatically after the user code finishes, to finalise construction of the
instance.
2017-12-12 16:43:16 +11:00
Damien George
d3f82bc425 py/mpstate.h: Remove obsolete comment about nlr_top being coded in asm. 2017-12-11 22:51:52 +11:00
Damien George
2759bec858 py: Extend nan-boxing config to have 47-bit small integers.
The nan-boxing representation has an extra 16-bits of space to store
small-int values, and making use of it allows to create and manipulate full
32-bit positive integers (ie up to 0xffffffff) without using the heap.
2017-12-11 22:39:12 +11:00
Damien George
9c02707356 py/objexcept: Use INT_FMT when printing errno value. 2017-12-11 22:38:30 +11:00
Damien George
30fd8484eb py/runtime: Use the Python stack when building *arg and **kwarg state.
With MICROPY_ENABLE_PYSTACK enabled the following language constructs no
longer allocate on the heap: f(*arg), f(**kwarg).
2017-12-11 13:49:09 +11:00
Damien George
1e5a33df41 py: Convert all uses of alloca() to use new scoped allocation API. 2017-12-11 13:49:09 +11:00
Damien George
02d830c035 py: Introduce a Python stack for scoped allocation.
This patch introduces the MICROPY_ENABLE_PYSTACK option (disabled by
default) which enables a "Python stack" that allows to allocate and free
memory in a scoped, or Last-In-First-Out (LIFO) way, similar to alloca().

A new memory allocation API is introduced along with this Py-stack.  It
includes both "local" and "nonlocal" LIFO allocation.  Local allocation is
intended to be equivalent to using alloca(), whereby the same function must
free the memory.  Nonlocal allocation is where another function may free
the memory, so long as it's still LIFO.

Follow-up patches will convert all uses of alloca() and VLA to the new
scoped allocation API.  The old behaviour (using alloca()) will still be
available, but when MICROPY_ENABLE_PYSTACK is enabled then alloca() is no
longer required or used.

The benefits of enabling this option are (or will be once subsequent
patches are made to convert alloca()/VLA):
- Toolchains without alloca() can use this feature to obtain correct and
  efficient scoped memory allocation (compared to using the heap instead
  of alloca(), which is slower).
- Even if alloca() is available, enabling the Py-stack gives slightly more
  efficient use of stack space when calling nested Python functions, due to
  the way that compilers implement alloca().
- Enabling the Py-stack with the stackless mode allows for even more
  efficient stack usage, as well as retaining high performance (because the
  heap is no longer used to build and destroy stackless code states).
- With Py-stack and stackless enabled, Python-calling-Python is no longer
  recursive in the C mp_execute_bytecode function.

The micropython.pystack_use() function is included to measure usage of the
Python stack.
2017-12-11 13:49:09 +11:00
Damien George
5b8998da6d py/runtime: Move mp_exc_recursion_depth to runtime and rename to raise.
For consistency this helper function is renamed to match the other
exception helpers, and moved to their location in runtime.c.
2017-12-11 13:49:09 +11:00
Paul Sokolovsky
e7fc765880 unix/mpconfigport: Disable uio.resource_stream().
This function was implemented as an experiment, and was enabled only in
unix port. To remind, it allows to access arbitrary files frozen as
source modules (vs bytecode).

However, further experimentation showed that the same functionality can
be implemented with frozen bytecode. The process requires more steps, but
with suitable toolset it doesn't matter patch. This process is:

1. Convert binary files into "Python resource module" with
tools/mpy_bin2res.py.
2. Freeze as the bytecode.
3. Use micropython-lib's pkg_resources.resource_stream() to access it.

In other words, the extra step is using tools/mpy_bin2res.py (because
there would be wrapper for uio.resource_stream() anyway).

Going frozen bytecode route allows more flexibility, and same/additional
efficiency:

1. Frozen source support can be disabled altogether for additional code
savings.
2. Resources could be also accessed as a buffer, not just as a stream.

There're few caveats too:

1. It wasn't actually profiled the overhead of storing a resource in
"Python resource module" vs storing it directly, but it's assumed that
overhead is small.
2. The "efficiency" claim above applies to the case when resource
file is frozen as the bytecode. If it's not, it actually will take a
lot of RAM on loading. But in this case, the resource file should not
be used (i.e. generated) in the first place, and micropython-lib's
pkg_resources.resource_stream() implementation has the appropriate
fallback to read the raw files instead. This still poses some distribution
issues, e.g. to deployable to baremetal ports (which almost certainly
would require freezeing as the bytecode), a distribution package should
include the resource module. But for non-freezing deployment, presense
of resource module will lead to memory inefficiency.

All the discussion above reminds why uio.resource_stream() was implemented
in the first place - to address some of the issues above. However, since
then, frozen bytecode approach seems to prevail, so, while there're still
some issues to address with it, this change is being made.

This change saves 488 bytes for the unix x86_64 port.
2017-12-10 02:38:23 +02:00
Paul Sokolovsky
d21d029d55 py/mkrules.mk: Add "clean-frozen" target to clean frozen script/modules dir.
This target removes any stray files (i.e. something not committed to git)
from scripts/ and modules/ dirs (or whatever FROZEN_DIR and FROZEN_MPY_DIR
is set to).

The expected workflow is:

1. make clean-frozen
2. micropython -m upip -p modules <packages_to_freeze>
3. make

As it can be expected that people may drop random thing in those dirs which
they can miss later, the content is actually backed up before cleaning.
2017-12-10 01:05:29 +02:00
Paul Sokolovsky
a35d923cdf py/map: Allow to trace rehashing operations. 2017-12-09 17:32:16 +02:00
Paul Sokolovsky
2b00181592 py/objfun: Factor out macro for initializing codestate.
This is second part of fun_bc_call() vs mp_obj_fun_bc_prepare_codestate()
common code refactor. This factors out code to initialize codestate
object. After this patch, mp_obj_fun_bc_prepare_codestate() is effectively
DECODE_CODESTATE_SIZE() followed by allocation followed by
INIT_CODESTATE(), and fun_bc_call() starts with that too.
2017-12-09 12:49:00 +02:00
Paul Sokolovsky
d72370def7 py/objfun, vm: Add comments on codestate allocation in stackless mode. 2017-12-09 11:01:34 +02:00
Paul Sokolovsky
fca1d1aa62 py/objfun: Factor out macro for decoding codestate size.
fun_bc_call() starts with almost the same code as
mp_obj_fun_bc_prepare_codestate(), the only difference is a way to
allocate the codestate object (heap vs stack with heap fallback).
Still, would be nice to avoid code duplication to make further
refactoring easier.

So, this commit factors out the common code before the allocation -
decoding and calculating codestate size. It produces two values,
so structured as a macro which writes to 2 variables passed as
arguments.
2017-12-09 09:19:34 +02:00
Paul Sokolovsky
dea3fb93c7 py/gc: In sweep debug output, print pointer as a pointer.
Or it will be truncated on a 64-bit platform.
2017-12-09 01:54:01 +02:00
Paul Sokolovsky
5453d88d5d py/gc: Factor out a macro to trace GC mark operations.
To allow easier override it for custom tracing.
2017-12-09 01:48:26 +02:00
Paul Sokolovsky
39dd89fe31 py/runtime: When tracing unary/binary ops, output op (method) name.
E.g.:

    >>> 1+1
    binary 26 __add__ 3 3

Output is similar to bytecode dump (numeric code, then op name).
2017-12-09 01:28:16 +02:00
Paul Sokolovsky
c0877cbb0d py/objint_longlong: Check for zero division/modulo. 2017-12-08 20:40:55 +02:00
Damien George
53e111800f py/asmbase: Revert removal of clearing of label offsets for native emit.
The assembler back-end for most architectures needs to know if a jump is
backwards in order to emit optimised machine code, and they do this by
checking if the destination label has been set or not.  So always reset
label offsets to -1 (this reverts partially the previous commit, with some
minor optimisation for the if-logic with the pass variable).
2017-12-08 19:07:00 +11:00
Damien George
f935bce3c5 py/{emitbc,asmbase}: Only clear emit labels to -1 when in debug mode.
Clearing the labels to -1 is purely a debugging measure.  For release
builds there is no need to do it as the label offset table should always
have the correct value assigned.
2017-12-08 18:23:23 +11:00
Paul Sokolovsky
9ef4be8b41 py/gc: Add CLEAR_ON_SWEEP option to debug mis-traced objects.
Accessing them will crash immediately instead still working for some time,
until overwritten by some other data, leading to much less deterministic
crashes.
2017-12-08 00:10:44 +02:00
Paul Sokolovsky
9ebc037eee py/malloc: Allow to use debug logging if !MICROPY_MALLOC_USES_ALLOCATED_SIZE.
This is mostly a workaround for forceful rebuilding of mpy-cross on every
codebase change. If this file has debug logging enabled (by patching),
mpy-cross build failed.
2017-12-07 18:01:40 +02:00
Paul Sokolovsky
88a8043a27 py/malloc: MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE.
Error out if they're set incompatibly.
2017-12-07 10:52:40 +02:00
Paul Sokolovsky
f5e097021c py/mpprint: Fix "%x" vs "%X" regression introduced in previous commit. 2017-12-07 10:31:14 +02:00
Paul Sokolovsky
5a10e63543 py/mpprint: Support "%lx" format on 64-bit systems.
Before that, the output was truncated to 32 bits. Only "%x" format is
handled, because a typical use is for addresses.

This refactor actually decreased x86_64 code size by 30 bytes.
2017-12-07 10:07:18 +02:00
Paul Sokolovsky
5f8ad284f8 py/mpprint: Make "%p" format work properly on 64-bit systems.
Before, the output was truncated to 32 bits.
2017-12-07 09:06:07 +02:00
Damien George
58f00d7c0e py/modbuiltins: Use standard arg-parsing helper func for builtin print.
This allows the function to raise an exception when unknown keyword args
are passed in.  This patch also reduces code size by (in bytes):

   bare-arm:   -24
minimal x86:   -76
   unix x64:   -56
unix nanbox:   -84
      stm32:   -40
    esp8266:   -68
     cc3200:   -48

Furthermore, this patch adds space (" ") to the set of ROM qstrs which
means it doesn't need to be put in RAM if it's ever used.
2017-12-05 12:14:57 +11:00
Paul Sokolovsky
62b96147e6 py: mp_call_function_*_protected(): Pass-thru return value if possible.
Return the result of called function. If exception happened, return
MP_OBJ_NULL. Allows to use mp_call_function_*_protected() with callbacks
returning values, etc.
2017-12-05 00:38:41 +02:00
Paul Sokolovsky
75d3c046da py/misc.h: Add m_new_obj_var_with_finaliser().
Similar to existing m_new_obj_with_finaliser().
2017-12-04 11:05:49 +02:00
Damien George
64f11470be py/objgenerator: Remove unreachable code for STOP_ITERATION case.
This commit essentially reverts aa9dbb1b03
where this if-condition was added.  It seems that even when that commit
was made the code was never reached by any tests, nor reachable by
analysis (see below).  The same is true with the code as it currently
stands: no test triggers this if-condition, nor any uasyncio examples.
Analysing the flow of the program also shows that it's not reachable:

==START==
-> to trigger this if condition mp_execute_bytecode() must return
   MP_VM_RETURN_YIELD with *sp==MP_OBJ_STOP_ITERATION

   -> mp_execute_bytecode() can only return MP_VM_RETURN_YIELD from the
      MP_BC_YIELD_VALUE bytecode, which can happen in 2 ways:

      -> 1) from a "yield <x>" in bytecode, but <x> must always be a proper
         object, never MP_OBJ_STOP_ITERATION; ==END1==

      -> 2) via yield from, via mp_resume() which must return
         MP_VM_RETURN_YIELD with ret_value==MP_OBJ_STOP_ITERATION, which
         can happen in 3 ways:

         -> 1) it delegates to mp_obj_gen_resume(); go back to ==START==

         -> 2) it returns MP_VM_RETURN_YIELD directly but with a guard that
            ret_val!=MP_OBJ_STOP_ITERATION; ==END2==

         -> 3) it returns MP_VM_RETURN_YIELD with ret_val set from
            mp_call_method_n_kw(), but mp_call_method_n_kw() must return a
            proper object, never MP_OBJ_STOP_ITERATION; ==END3==

The above shows there is no way to trigger the if-condition and it can be
removed.
2017-11-30 12:06:41 +11:00
Damien George
74fad3536b py/gc: In gc_realloc, convert pointer sanity checks to assertions.
These checks are assumed to be true in all cases where gc_realloc is
called with a valid pointer, so no need to waste code space and time
checking them in a non-debug build.
2017-11-29 17:17:08 +11:00
Damien George
8e323b8fa8 py/qstr: Rewrite find_qstr to make manifest that it returns a valid ptr.
So long as the input qstr identifier is valid (below the maximum number of
qstrs) the function will always return a valid pointer.  This patch
eliminates the "return 0" dead-code.
2017-11-29 17:01:39 +11:00
Damien George
3990a52c0f py: Annotate func defs with NORETURN when their corresp decls have it. 2017-11-29 15:43:40 +11:00
Damien George
2161d6b603 py/objdict: Reuse dict-view key iterator for standard dict iterator.
It has equivalent behaviour and reusing it saves some code bytes.
2017-11-27 23:40:31 +11:00
Damien George
84895f1a21 py/parsenum: Improve parsing of floating point numbers.
This patch improves parsing of floating point numbers by converting all the
digits (integer and fractional) together into a number 1 or greater, and
then applying the correct power of 10 at the very end.  In particular the
multiple "multiply by 0.1" operations to build a fraction are now combined
together and applied at the same time as the exponent, at the very end.

This helps to retain precision during parsing of floats, and also includes
a check that the number doesn't overflow during the parsing.  One benefit
is that a float will have the same value no matter where the decimal point
is located, eg 1.23 == 123e-2.
2017-11-27 12:51:52 +11:00
Damien George
5e34a113ea py/runtime: Add MP_BINARY_OP_CONTAINS as reverse of MP_BINARY_OP_IN.
Before this patch MP_BINARY_OP_IN had two meanings: coming from bytecode it
meant that the args needed to be swapped, but coming from within the
runtime meant that the args were already in the correct order.  This lead
to some confusion in the code and comments stating how args were reversed.
It also lead to 2 bugs: 1) containment for a subclass of a native type
didn't work; 2) the expression "{True} in True" would illegally succeed and
return True.  In both of these cases it was because the args to
MP_BINARY_OP_IN ended up being reversed twice.

To fix these things this patch introduces MP_BINARY_OP_CONTAINS which
corresponds exactly to the __contains__ special method, and this is the
operator that built-in types should implement.  MP_BINARY_OP_IN is now only
emitted by the compiler and is converted to MP_BINARY_OP_CONTAINS by
swapping the arguments.
2017-11-24 14:48:23 +11:00
Damien George
5b2f62aff3 py/opmethods: Include the correct header for binary op enums.
By directly including runtime0.h the mpconfig.h settings are not included
and so the enums in runtime0.h can be incorrect.
2017-11-24 12:16:21 +11:00
Damien George
9783ac282e py/runtime: Simplify handling of containment binary operator.
In mp_binary_op, there is no need to explicitly check for type->getiter
being non-null and raising an exception because this is handled exactly by
mp_getiter().  So just call the latter unconditionally.
2017-11-24 12:07:12 +11:00
Damien George
d5cf5f70fd py/modbuiltins: Slightly simplify code in builtin round(). 2017-11-22 15:51:51 +11:00
Damien George
a07fc5b640 py/objfloat: Allow float() to parse anything with the buffer protocol.
This generalises and simplifies the code and follows CPython behaviour.
2017-11-21 15:01:38 +11:00
Paul Sokolovsky
8667a5f053 py/objnamedtuple: Allow to reuse namedtuple basic functionality.
By declaring interface in objnamedtuple.h and introducing a helper
allocation function.
2017-11-20 09:30:06 +02:00
Damien George
da154fdaf9 py: Add config option to disable multiple inheritance.
This patch introduces a new compile-time config option to disable multiple
inheritance at the Python level: MICROPY_MULTIPLE_INHERITANCE.  It is
enabled by default.

Disabling multiple inheritance eliminates a lot of recursion in the call
graph (which is important for some embedded systems), and can be used to
reduce code size for ports that are really constrained (by around 200 bytes
for Thumb2 archs).

With multiple inheritance disabled all tests in the test-suite pass except
those that explicitly test for multiple inheritance.
2017-11-20 16:18:50 +11:00
Damien George
8d956c26d1 py/objstr: When constructing str from bytes, check for existing qstr.
This patch uses existing qstr data where possible when constructing a str
from a bytes object.
2017-11-16 14:02:28 +11:00
Damien George
1f1d5194d7 py/objstr: Make mp_obj_new_str_of_type check for existing interned qstr.
The function mp_obj_new_str_of_type is a general str object constructor
used in many places in the code to create either a str or bytes object.
When creating a str it should first check if the string data already exists
as an interned qstr, and if so then return the qstr object.  This patch
makes the function have such behaviour, which helps to reduce heap usage by
reusing existing interned data where possible.

The old behaviour of mp_obj_new_str_of_type (which didn't check for
existing interned data) is made available through the function
mp_obj_new_str_copy, but should only be used in very special cases.

One consequence of this patch is that the following expression is now True:

    'abc' is ' abc '.split()[0]
2017-11-16 13:53:04 +11:00