Compare commits

..

164 Commits

Author SHA1 Message Date
Damien George
552f7c40a0 docs: Bump version to 1.3.9. 2015-01-25 00:10:07 +00:00
Damien George
ad33e2465c stmhal: Disable MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE.
It uses RAM and on pyboard we are generally tight on RAM, so disable
this optimisation for general builds.  If users need the speed then
they can build their own version.  Maybe in the future we can have
different versions of pyboard firmware built with different tradeoffs.
2015-01-24 23:45:37 +00:00
Paul Sokolovsky
31c1f1300e modffi: 's' (string) return type: handle NULL properly (return None). 2015-01-25 01:36:14 +02:00
Damien George
32444b759a py: Don't use anonymous unions, name them instead.
This makes the code (more) compatible with the C99 standard.
2015-01-24 23:14:12 +00:00
Damien George
5c670acb1f py: Be more machine-portable with size of bit fields. 2015-01-24 23:12:58 +00:00
David Steinberg
4c1a7e0d6a tests: Update float2int tests for new range classifications
- Tests vary based on build configuration (32/64-bit and internal int type).
- Added tests for exceptions raised on overflow of int type.
2015-01-24 21:05:16 +00:00
David Steinberg
0fb17f6ef4 py: Use float-to-int classifications for mp_obj_new_int_from_float() functions 2015-01-24 20:54:28 +00:00
David Steinberg
ca377b10de py: Add float-to-int classification function 2015-01-24 20:54:28 +00:00
David Steinberg
8d427b7ab7 py: Fix issue in mpz_set_from_float() when mp_int_t is larger than float 2015-01-24 20:54:28 +00:00
David Steinberg
c585ad1020 py: Move mp_float_t related defines to misc.h 2015-01-24 20:54:28 +00:00
stijn
6b636738b2 py: Fix segfault in namedtuple when name is a non-interned string
- namedtuple was wrongly using MP_OBJ_QSTR_VALUE instead of mp_obj_str_get_qstr,
so when passed a non-interned string it would segfault; fix this by using mp_obj_str_get_qstr
- store the namedtuple field names as qstrs so it is not needed to use mp_obj_str_get_qstr
everytime the field name has to be accessed. This also slighty increases performance when
fetching attributes
2015-01-24 20:21:09 +00:00
Damien George
23342c09ff stmhal: Bug fix for usocket's accept and setsockopt methods.
accept might raise an exception, in which case the new socket is not
fully created.  It has a finaliser so will run close() method when GC'd.
Before this patch close would try to close an invalid socket.  Now
fixed.

setsockopt took address of stack value which became out of scope.  Now
fixed.
2015-01-24 15:07:50 +00:00
Paul Sokolovsky
91232d3850 binary: Rework array accessors. They work with native, not stdint types. 2015-01-24 03:18:33 +02:00
Paul Sokolovsky
ca3dbb8d8b stream: readall(): Make sure there's a trailing NUL char. 2015-01-24 00:22:47 +02:00
Paul Sokolovsky
66b060f3e6 tests: Fix typo in file_long_read3.py. 2015-01-23 19:00:02 +02:00
Paul Sokolovsky
444331c07f modujson: .loads(): Handle more whitespace characters. 2015-01-23 18:41:29 +02:00
Paul Sokolovsky
1f04336b23 tests: Add extra test for reading multiple of internal chunk size. 2015-01-23 18:18:11 +02:00
Paul Sokolovsky
425f952a1e stream: Fix readall() implementation in respect to NUL terminator bytes.
After vstr refactor. Fixes #1084.
2015-01-23 17:59:37 +02:00
Paul Sokolovsky
220d21e1bf tests: Add testcase for reading amounts bigger than buffer/chunk size. 2015-01-23 16:42:02 +02:00
Paul Sokolovsky
344e15b1ae objstr: Remove code duplication and unbreak Windows build.
There was really weird warning (promoted to error) when building Windows
port. Exact cause is still unknown, but it uncovered another issue:
8-bit and unicode str_make_new implementations should be mutually exclusive,
and not built at the same time. What we had is that bytes_decode() pulled
8-bit str_make_new() even for unicode build.
2015-01-23 02:15:56 +02:00
Paul Sokolovsky
6113eb2f33 objstr*: Use separate names for locals_dict of 8-bit and unicode str's.
To somewhat unbreak -DSTATIC="" compile.
2015-01-23 02:05:58 +02:00
Damien George
e5bcbcdebd py: Allow asmx64 to compile with -Wsign-compare.
See issue #699.
2015-01-22 14:08:58 +00:00
Damien George
6d1f5070ce lib/libm: Add frexp and modf functions; use in stmhal; add tests.
Addresses issue #1081.
2015-01-22 13:48:29 +00:00
Damien George
bd9c1ad601 stmhal: Make CC3K object static, so it's only registered once as NIC. 2015-01-22 00:17:40 +00:00
Damien George
8b77e3dd2f stmhal: Put mod_network_nic_list in global root-pointer state.
It needs to be scanned by GC.  Thanks to Daniel Campora.
2015-01-22 00:16:41 +00:00
Damien George
77089bebd4 py: Add comments for vstr_init and mp_obj_new_str. 2015-01-21 23:18:02 +00:00
Damien George
05005f679e py: Remove mp_obj_str_builder and use vstr instead.
With this patch str/bytes construction is streamlined.  Always use a
vstr to build a str/bytes object.  If the size is known beforehand then
use vstr_init_len to allocate only required memory.  Otherwise use
vstr_init and the vstr will grow as needed.  Then use
mp_obj_new_str_from_vstr to create a str/bytes object using the vstr
memory.

Saves code ROM: 68 bytes on stmhal, 108 bytes on bare-arm, and 336 bytes
on unix x64.
2015-01-21 23:18:02 +00:00
Damien George
0b9ee86133 py: Add mp_obj_new_str_from_vstr, and use it where relevant.
This patch allows to reuse vstr memory when creating str/bytes object.
This improves memory usage.

Also saves code ROM: 128 bytes on stmhal, 92 bytes on bare-arm, and 88
bytes on unix x64.
2015-01-21 23:17:27 +00:00
Paul Sokolovsky
2e526ff1a1 modffi: Support return values of mp_obj_t type. 2015-01-22 01:09:17 +02:00
Paul Sokolovsky
8064892c9b builtinimport: Make sure that qstr is used properly to load frozen modules. 2015-01-21 23:14:46 +02:00
Damien George
b6e6b5277f py: Implement proper re-raising in native codegen's finally handler.
This allows an exception to propagate correctly through a finally
handler.
2015-01-21 17:00:01 +00:00
Damien George
962a5d50c9 py: Implement __reversed__ slot.
Addresses issue #1073.
2015-01-21 00:19:42 +00:00
Dave Hylands
d7f199465f stmhal: Add support for FEZ Cerb40 II board from ghielectronics.com. 2015-01-21 00:11:04 +00:00
Damien George
73533247cb docs: Fix frequency info for DAC.triangle. 2015-01-20 23:56:10 +00:00
stijn
bf19541f46 py: Prevent segfault for operations on closed StringIO.
Addresses issue #1067.
2015-01-20 23:50:43 +00:00
Paul Sokolovsky
0ab3fc3805 modffi: Support open own executable using open(None). 2015-01-21 00:38:06 +02:00
Damien George
50149a5730 py: Use mp_arg_check_num in some _make_new functions.
Reduces stmhal code size by about 250 bytes.
2015-01-20 14:11:27 +00:00
Damien George
ff8dd3f486 py, unix: Allow to compile with -Wunused-parameter.
See issue #699.
2015-01-20 12:47:20 +00:00
Damien George
50912e7f5d py, unix, stmhal: Allow to compile with -Wshadow.
See issue #699.
2015-01-20 11:55:10 +00:00
Paul Sokolovsky
640e0b221e py: Implement very simple frozen modules support.
Only modules (not packages) supported now. Source modules can be converted
to frozen module structures using tools/make-frozen.py script.
2015-01-20 11:52:12 +02:00
Paul Sokolovsky
438b3d26b5 esp8266: Add missing hard_reset qstr. 2015-01-18 00:37:46 +02:00
Paul Sokolovsky
f1700a5154 esp8266:modpyb: Implement hard_reset(). 2015-01-18 00:30:14 +02:00
Damien George
51ef28a9d6 unix: Update .gitignore for "fast" and "minimal" builds. 2015-01-16 18:05:31 +00:00
Damien George
3926c72dd2 unix: Add target to build "minimal" uPy interpreter. 2015-01-16 18:03:01 +00:00
Damien George
963a5a3e82 py, unix: Allow to compile with -Wsign-compare.
See issue #699.
2015-01-16 17:47:07 +00:00
Paul Sokolovsky
f12ea7c7ed esp8266: Implement task-based, event-driven interface with UART.
This enables proper interfacing with underlying OS - MicroPython doesn't
run the main loop, OS does, MicroPython just gets called when some event
takes place.
2015-01-16 19:20:17 +02:00
Damien George
0abb5609b0 py: Remove unnecessary id_flags argument from emitter's load_fast.
Saves 24 bytes in bare-arm.
2015-01-16 12:24:49 +00:00
Paul Sokolovsky
2276eb8084 minimal: Make #if indent consistent. 2015-01-16 01:53:33 +02:00
Paul Sokolovsky
d7337f288e minimal: Support even-driven REPL. 2015-01-16 01:38:24 +02:00
Paul Sokolovsky
87bc8e2b3d pyexec: Add event-driven variant pyexec_friendly_repl().
pyexec_friendly_repl_process_char() and friends, useful for ports which
integrate into existing cooperative multitasking system.

Unlike readline() refactor before, this was implemented in less formal,
trial&error process, minor functionality regressions are still known
(like soft&hard reset support). So, original loop-based pyexec_friendly_repl()
is left intact, specific implementation selectable by config setting.
2015-01-16 01:30:42 +02:00
Paul Sokolovsky
c6b8750c14 esp8266: Use dedicated heap allocated as static array.
We cannot assume that all memory belongs to us - it actually belongs to
ESP8266 OS.
2015-01-15 00:36:03 +02:00
Damien George
d2d64f00fb py: Add "default" to switches to allow better code flow analysis.
This helps compiler produce smaller code.  Saves 124 bytes on stmhal and
bare-arm.
2015-01-14 21:32:42 +00:00
Damien George
65ef6b768c py: Only allocate strings/bytes once for load_const_obj. 2015-01-14 21:17:27 +00:00
Damien George
d95b519aa1 unix, windows: Don't call mp_unix_mark_exec on windows. 2015-01-14 11:43:51 +00:00
Damien George
d9dc6fff21 py: Allocate memory for assembled code at start of PASS_EMIT.
Previously was allocating at end of PASS_COMPUTE, and this pass was
being run twice, so memory was being allocated twice.
2015-01-14 00:38:33 +00:00
Damien George
bc47c287df travis, minimal: Install gcc-multilib for -m32; use /bin/echo for test. 2015-01-14 00:26:39 +00:00
Damien George
1e1779eacf py: Reluctantly add an extra pass to bytecode compiler.
Bytecode also needs a pass to compute the stack size.  This is because
the state size of the bytecode function is encoded as a variable uint,
so we must know the value of this uint before we encode it (otherwise
the size of the generated code changes from one pass to the next).

Having an entire pass for this seems wasteful (in time).  Alternative is
to allocate fixed space for the state size (would need 3-4 bytes to be
general, when 1 byte is usually sufficient) which uses a bit of extra
RAM per bytecode function, and makes the code less elegant in places
where this uint is encoded/decoded.

So, for now, opt for an extra pass.
2015-01-14 00:20:28 +00:00
Damien George
2127e9a844 py, unix: Trace root pointers with native emitter under unix port.
Native code has GC-heap pointers in it so it must be scanned.  But on
unix port memory for native functions is mmap'd, and so it must have
explicit code to scan it for root pointers.
2015-01-14 00:11:09 +00:00
Damien George
c935d69f74 py: Make compiler not crash when default except is not last. 2015-01-13 23:33:16 +00:00
Damien George
d6ed6702f7 py/showbc.c: Handle new LOAD_CONST_OBJ opcode, and opcodes with cache. 2015-01-13 23:08:47 +00:00
Damien George
4c81ba8015 py: Never intern data of large string/bytes object; add relevant tests.
Previously to this patch all constant string/bytes objects were
interned by the compiler, and this lead to crashes when the qstr was too
long (noticeable now that qstr length storage defaults to 1 byte).

With this patch, long string/bytes objects are never interned, and are
referenced directly as constant objects within generated code using
load_const_obj.
2015-01-13 16:21:23 +00:00
Damien George
dab1385177 py: Add load_const_obj to emitter, add LOAD_CONST_OBJ to bytecode.
This allows to directly load a Python object to the Python stack.  See
issue #722 for background.
2015-01-13 15:55:54 +00:00
Damien George
d710cef661 minimal: Add simple test; build and run minimal test on Travis CI. 2015-01-13 12:39:29 +00:00
Damien George
a45b042e59 minimal/Makefile: Remove unnecessary -I of py/ dir. 2015-01-13 12:23:13 +00:00
Paul Sokolovsky
f41df1e611 minimal: Add "run" make target to run emulated build with suitable tty config. 2015-01-13 04:07:03 +02:00
Paul Sokolovsky
5ebabcda41 minimal: Convert "bare-arm" port to "minimal" port.
This enable libc functions, GC, and line-editing function. Also, UART
emulation for POSIX systems is added. Emulation build is set as default.
2015-01-13 04:02:56 +02:00
Paul Sokolovsky
d511a20a6b minimal: New port, intended to represent minimal working code.
Unlike bare-arm, which is mostly intended to show raw interpreter size,
without library and support code dependencies. This port is intended to
be a better base to start new ports, and also will include emulation
build to allow debug some aspects of embedded targets on POSIX systems.

This initial commit is verbatim copy of bare-arm code.
2015-01-13 03:17:47 +02:00
Damien George
bbf5cd01e3 py: Allow to compile with -Wstrict-prototypes. 2015-01-12 22:45:35 +00:00
Damien George
30d8a82220 py: Allow to compile with -Wredundant-decls. 2015-01-12 22:41:55 +00:00
Damien George
abc1959e2c py, unix, lib: Allow to compile with -Wold-style-definition. 2015-01-12 22:34:38 +00:00
Damien George
cd34207409 py: Can compile with -Wmissing-declarations and -Wmissing-prototypes. 2015-01-12 22:30:49 +00:00
Damien George
3dd1c0a88a py: Make a function static and comment out those not used. 2015-01-12 22:22:46 +00:00
Damien George
0178aa9a11 py, unix: Allow to compile with -Wdouble-promotion.
Ref issue #699.
2015-01-12 21:56:35 +00:00
Damien George
b58da9420c qemu-arm: Disable basics/memoryerror.py test. 2015-01-12 16:32:14 +00:00
Damien George
131185a2b8 stmhal: Add MICROPY_HW_USB_OTG_ID_PIN config, set for relevant boards.
This config option is for the USB OTG pin, pin A10.  This is used on
some boards but not others.  Eg PYBv3 uses PA10 for LED(2), so it
shouldn't be used for OTG ID (actually PA10 is multiplexed on this
board, but defaults to LED(2)).

Partially addresses issue #1059.
2015-01-12 16:13:29 +00:00
Damien George
7630d9ca0e travis: grep for failure in qemu-arm output if tests fail. 2015-01-12 15:50:08 +00:00
Damien George
5b76e3b75e windows: Enable MICROPY_STACK_CHECK. 2015-01-12 15:34:53 +00:00
Damien George
99dde4ed1f qemu-arm: Enable GC and native code-gen; enable more tests. 2015-01-12 12:07:42 +00:00
Paul Sokolovsky
3f9f9cac75 lib/mp-readline: Refactor to support coroutine/event-driven usage.
readline_process_char() can be fed character by character, for example,
received from external event loop. This will allow to integrate MicroPython
into cooperative multitasking systems.
2015-01-12 04:36:57 +02:00
Paul Sokolovsky
708574b082 teensy: Update for readline module moved to lib/. 2015-01-12 04:27:36 +02:00
Paul Sokolovsky
06e9cb688b esp8266: Update for readline module moved to lib/. 2015-01-12 04:27:36 +02:00
Paul Sokolovsky
a7bcb218fe stmhal: Move readline code to lib/mp-readline/. 2015-01-12 04:15:35 +02:00
Damien George
99ab64ffd4 py/makeqstrdata.py: Make it work again with both Python2 and Python3. 2015-01-11 22:40:38 +00:00
Damien George
95836f8439 py: Add MICROPY_QSTR_BYTES_IN_LEN config option, defaulting to 1.
This new config option sets how many fixed-number-of-bytes to use to
store the length of each qstr.  Previously this was hard coded to 2,
but, as per issue #1056, this is considered overkill since no-one
needs identifiers longer than 255 bytes.

With this patch the number of bytes for the length is configurable, and
defaults to 1 byte.  The configuration option filters through to the
makeqstrdata.py script.

Code size savings going from 2 to 1 byte:
- unix x64 down by 592 bytes
- stmhal down by 1148 bytes
- bare-arm down by 284 bytes

Also has RAM savings, and will be slightly more efficient in execution.
2015-01-11 22:27:30 +00:00
Damien George
6942f80a8f py: Add qstr cfg capability; generate QSTR_NULL and QSTR_ from script. 2015-01-11 22:06:53 +00:00
Damien George
e233a55a29 py: Remove unnecessary BINARY_OP_EQUAL code that just checks pointers.
Previous patch c38dc3ccc7 allowed any
object to be compared with any other, using pointer comparison for a
fallback.  As such, existing code which checked for this case is no
longer needed.
2015-01-11 21:07:15 +00:00
Damien George
c38dc3ccc7 py: Implement fallback for equality check for all types.
Return "not equal" for objects that don't implement equality check.
This is as per Python specs.
2015-01-11 15:13:18 +00:00
Damien George
ec21405821 py: Add (commented out) code to gc_dump_alloc_table for qstr info. 2015-01-11 14:37:06 +00:00
Damien George
56e1f99ca1 py/makeqstrdata.py: Add more allowed qstr characters; escape quot. 2015-01-11 14:16:24 +00:00
Damien George
01418e9690 py: Fix hard-coded hash for empty qstr (was 0x0000 now 0x1505). 2015-01-11 14:15:45 +00:00
Damien George
ddd1e18801 py: Add config option MICROPY_COMP_MODULE_CONST for module consts.
Compiler optimises lookup of module.CONST when enabled (an existing
feature).  Disabled by default; enabled for unix, windows, stmhal.
Costs about 100 bytes ROM on stmhal.
2015-01-10 14:07:24 +00:00
Paul Sokolovsky
7bfe4b21b9 tests: Make ffi_callback.py be able to run on uclibc and macosx.
Similar to ffi_float.py.
2015-01-10 00:35:48 +02:00
Damien George
58056b0f43 py: Fix handling of "0" mpz in some functions. 2015-01-09 20:58:58 +00:00
Damien George
f5465b9eb0 stmhal: Reclaim 72 bytes of stack by factoring out flash init code. 2015-01-09 20:38:23 +00:00
Damien George
5d48f234d2 py: Make mem_info print correct remaining stack bytes. 2015-01-09 20:37:49 +00:00
Damien George
a9a0862078 windows: Enable MICROPY_PY_MICROPYTHON_MEM_INFO. 2015-01-09 20:30:26 +00:00
Damien George
89deec0bab py: Add MICROPY_PY_MICROPYTHON_MEM_INFO to enable mem-info funcs.
This allows to enable mem-info functions in micropython module, even if
MICROPY_MEM_STATS is not enabled.  In this case, you get mem_info and
qstr_info but not mem_{total,current,peak}.
2015-01-09 20:12:54 +00:00
Damien George
4a5895c4eb py: Disable stack checking by default; enable on most ports. 2015-01-09 00:10:55 +00:00
Damien George
85e8e2ed5b qemu-arm: Add 'test' target to Makefile to run and verify test suite.
Replaces RUN_TEST=1 definition; now "make test" in qemu-arm directory
will run tests/basics/ and check that they all succeed.

This patch also enables the test on Travis CI.
2015-01-09 00:03:21 +00:00
Damien George
3990dcfcd7 docs: Add note about maximum frequency of busses. 2015-01-08 22:54:26 +00:00
Damien George
14fab60baf qemu-arm: Get "make RUN_TESTS=1" compiling after changes to core. 2015-01-08 22:12:44 +00:00
Damien George
d2d0648ad0 qemu-arm: Set stack limit in main. 2015-01-08 21:40:35 +00:00
Damien George
7a53ac8ec2 stmhal: Allow to build without float support if wanted. 2015-01-08 17:55:55 +00:00
Damien George
c33ecb83ba tests: Add test for when instance member overrides class member. 2015-01-08 17:48:44 +00:00
Damien George
5b7aa294e0 py: Fix nlr mp_state_ctx symbol error for Mac. 2015-01-08 16:24:44 +00:00
Damien George
19b3fea6a8 tests: Separate out test cases that rely on float support to float/ dir. 2015-01-08 15:41:37 +00:00
Damien George
115187f7ce unix: Allow to compile with float support disabled. 2015-01-08 15:41:11 +00:00
stijn
afd6c8e1d2 Remove obsolete bss-related code/build features
GC for unix/windows builds doesn't make use of the bss section anymore,
so we do not need the (sometimes complicated) build features and code related to it
2015-01-08 15:29:44 +01:00
Damien George
181bfb6db2 stmhal: Add MICROPY_HW_USB_VBUS_DETECT_PIN option, for boards without it
Since all currently supported boards use pin A9 for this function, the
value of the macro MICROPY_HW_USB_VBUS_DETECT_PIN is not actually used,
just the fact that it is defined.

Addresses issue #1048.
2015-01-07 23:54:57 +00:00
Damien George
c223df5113 drivers/cc3000: Fix call to extint_register. 2015-01-07 23:54:19 +00:00
Damien George
3b51b3e90f stmhal: Collect all root pointers together in 1 place.
A GC in stmhal port now only scans true root pointers, not entire BSS.
This reduces base GC time from 1700ms to 900ms.
2015-01-07 23:38:50 +00:00
Paul Sokolovsky
7a0636e80a docs: Add initial "uctypes" modules docs. WIP. 2015-01-08 00:17:10 +02:00
Damien George
7ee91cf861 py: Add option to cache map lookup results in bytecode.
This is a simple optimisation inspired by JITing technology: we cache in
the bytecode (using 1 byte) the offset of the last successful lookup in
a map. This allows us next time round to check in that location in the
hash table (mp_map_t) for the desired entry, and if it's there use that
entry straight away.  Otherwise fallback to a normal map lookup.

Works for LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR and STORE_ATTR opcodes.

On a few tests it gives >90% cache hit and greatly improves speed of
code.

Disabled by default.  Enabled for unix and stmhal ports.
2015-01-07 21:07:23 +00:00
Damien George
b4b10fd350 py: Put all global state together in state structures.
This patch consolidates all global variables in py/ core into one place,
in a global structure.  Root pointers are all located together to make
GC tracing easier and more efficient.
2015-01-07 20:33:00 +00:00
Damien George
ad2307c92c py: Temporary fix for conversion of float to int when fits in small int.
Addresses issue #1044 (see also #1040).  Could do with a better fix.
2015-01-07 12:10:47 +00:00
Paul Sokolovsky
d8bfd77ad5 showbc: Show conditional jump destination as unsigned value.
This is consistent with how BC_JUMP was handled before. We never show jumps
destinations relative to jump instrucion itself, only relative to beginning
of function. Another useful way to show them as absolute (real memory
address), and this change makes result expected and consistent with how
BC_JUMP is shown.
2015-01-07 00:29:15 +02:00
Damien George
b27c9876ea docs: For Windows USB CDC driver setup, add link to existing PDF guide. 2015-01-06 16:09:49 +00:00
Paul Sokolovsky
343ca1e63a objarray: Make sure that longint works as bytearray size. 2015-01-04 17:19:16 +02:00
stijn
51af362e31 msvc: Define no-op MP_LIKELY/UNLIKELY since there's no __builtin_expect 2015-01-04 13:29:02 +02:00
Paul Sokolovsky
ed3b20aae8 modbuiltins.c: Fix NULL vs MP_OBJ_NULL usage. 2015-01-04 13:26:43 +02:00
Paul Sokolovsky
ff8e35b42e objstr: Common subexpression elimination for vstr_str(field_name). 2015-01-04 13:23:44 +02:00
Paul Sokolovsky
c114496641 objstr: Implement kwargs support for str.format(). 2015-01-04 00:26:31 +02:00
Paul Sokolovsky
ae58795c44 unix: Enable -fno-crossjumping for fast build.
Confirmed that it improves perfomance of simple "for i in range(N): pass"
loop by 15% on Core2.
2015-01-03 21:15:02 +02:00
Damien George
6fd4b36bc5 py: Raise exception if trying to convert inf/nan to int. 2015-01-02 23:04:09 +00:00
David Steinberg
6e0b6d02db py: Fix float to int conversion for large exponents. 2015-01-02 22:31:41 +00:00
stijn
ffc96a901a msvc: Use single build target for dealing with generated files
Remove some duplication in the code for generating
qstrdefs.generated.h and py-version.h
2015-01-02 16:55:02 +01:00
stijn
fbfd3554fa msvc: Fix unresolved mp_arg_error_terse_mismatch since 7f23384
The compiler treats `if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE)` as
a normal statement and generates assembly for it in degug mode as if MICROPY_ERROR_REPORTING
is an actual symbol instead of a preprocessor definition.
As such linking fails because mp_arg_error_terse_mismatch is not defined when
MICROPY_ERROR_REPORTING_TERSE is detailed or normal.
2015-01-02 16:53:54 +01:00
stijn
8dec62a1a4 msvc: Define main build/include directories in a single location
- Use a single file env.props for defining the main directories used when building.
  env.props resolves the base directory and defines overridable output directories,
  and is used by all other build files.
- Fix the build currently failing, basically because the preprocessing command for generating
  qstrdefs uses different include directories than the build itself does.
  (specifically, qstrdefs.h uses #include "py/mpconfig.h" since the fixes for #1022
  in 51dfcb4, so we need to use the base directory as include directory, not the py dir itself).
  So define a single variable containing the include directories instead and use it where needed.
2015-01-02 16:52:07 +01:00
Damien George
fd40a9c38e py: Make GC's STACK_SIZE definition a proper MICROPY_ config variable. 2015-01-01 22:04:46 +00:00
Damien George
872a82970d py: Fix windows external name error for nlr_top. 2015-01-01 22:03:44 +00:00
Damien George
8a2347723e py: Move global variable nlr_top to one place, in a .c file.
This reduces dependency on assembler, and allows to consolidate global
variables in the future.
2015-01-01 21:47:58 +00:00
Damien George
0b2a60acbe windows: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:21:46 +00:00
Damien George
fe7d542352 esp8266: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:16:58 +00:00
Damien George
4ef4ffe1c5 qemu-arm: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:15:38 +00:00
Damien George
c2e22d66da bare-arm: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:14:42 +00:00
Damien George
b68d98d61c teensy: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:13:30 +00:00
Damien George
2cf6dfa280 stmhal: Prefix includes with py/; remove need for -I../py. 2015-01-01 21:06:20 +00:00
Damien George
b36be5ff51 unix-cpy: Prefix includes with py/; remove need for -I../py. 2015-01-01 20:41:52 +00:00
Damien George
6d7e47087f unix: Prefix includes with py/; remove need for -I../py. 2015-01-01 20:40:19 +00:00
Damien George
3765ea419a extmod: Prefix py/ for includes from py core directory. 2015-01-01 20:35:21 +00:00
Damien George
51dfcb4bb7 py: Move to guarded includes, everywhere in py/ core.
Addresses issue #1022.
2015-01-01 20:32:09 +00:00
Paul Sokolovsky
db1ac360c3 emitnative: Disable warning in delete_fast for now (breaks test). 2015-01-01 22:09:18 +02:00
Paul Sokolovsky
8a8c1fc82f py: Add basic framework for issuing compile/runtime warnings. 2015-01-01 22:09:18 +02:00
Damien George
ebde3c694f py: Add guarded includes for asm-based headers. 2015-01-01 18:07:43 +00:00
Damien George
ddbcc79550 docs: Add quickref info about Servo; improve Servo docs. 2015-01-01 18:00:45 +00:00
Radomir Dopieralski
ce5b5caf8c Add a command for converting the WAV files
Add a command for converting the WAV files to the amp skin tutorial, so that people can use their own files easily.
2015-01-01 17:56:05 +00:00
Damien George
84e0cf0d21 py: Change namedtuple error messages to reduce code size.
We are not word-for-word compatible with CPython exceptions, so we are
free to make them short but informative in order to reduce code size.
Also, try to make messages the same as existing ones where possible.
2015-01-01 15:43:25 +00:00
Damien George
7f23384d49 py: Make terse_arg_mismatch a global function and use it elsewhere.
Reduces code size when MICROPY_ERROR_REPORTING_TERSE is selected.
2015-01-01 15:33:50 +00:00
Paul Sokolovsky
276159e5dd objnamedtuple: Make sure to initialize type structure completely. 2015-01-01 15:31:51 +02:00
stijn
021dc44009 py: Allow keyword arguments for namedtuple 2015-01-01 14:53:23 +02:00
stijn
12340147b0 py: Use sequence of strings for named tuple initialization
- remove single string initialization style
- take list of strings instead
- store list in the type for fast lookup
2015-01-01 14:53:23 +02:00
stijn
8422cac088 msvc: Support py/*.h includes per #1022 2015-01-01 13:10:54 +01:00
Damien George
e0ac194f4f py: Fix rshift and not of zero/one edge cases in mpz.
Addresses issue #1027.
2014-12-31 19:35:01 +00:00
Damien George
816a46a4ab tests: Disable float/float2int.py on pyboard (needs double prec). 2014-12-31 18:46:18 +00:00
Paul Sokolovsky
2c75665445 objstr: Fix %d-formatting of floats. 2014-12-31 02:21:19 +02:00
Paul Sokolovsky
8a2cc1c7e4 stmhal: Add fake implementation of __aeabi_f2lz().
To make mp_obj_new_int_from_float() somehow work.
2014-12-30 00:52:41 +02:00
Paul Sokolovsky
5f68094e10 py: mp_obj_new_int_from_float() supported only for MICROPY_PY_BUILTINS_FLOAT. 2014-12-30 00:34:54 +02:00
Paul Sokolovsky
f79cd6a233 py: Implement mp_obj_new_int_from_float() for MICROPY_LONGINT_IMPL_NONE. 2014-12-30 00:33:32 +02:00
Paul Sokolovsky
12033df511 py: Partially fix float to int conversion.
This fixes conversion when float type has more mantissa bits than small int,
and float value has small exponent. This is for example the case of 32-bit
platform using doubles, and converting value of time.time(). Conversion of
floats with larg exponnet is still not handled correctly.
2014-12-30 00:22:50 +02:00
Damien George
e3fa8278b4 tools: Add script to generate a ChangeLog file.
We don't have an explicit ChangeLog file, but don't really need one
because we use a good version control system.  This script is useful if
you need a pretty-printed ChangeLog for some reason.
2014-12-29 19:03:25 +00:00
Damien George
9ddbe291c4 py: Add include guards to mpconfig,misc,qstr,obj,runtime,parsehelper. 2014-12-29 01:02:19 +00:00
Damien George
f89d659e3b py: In VM, for selective ip saving, store 1 byte past last opcode.
This is for efficiency, so we don't need to subtract 1 from the ip
before storing it to code_state->ip.  It saves a lot of ROM bytes on
unix and stmhal.
2014-12-29 00:29:59 +00:00
Paul Sokolovsky
23f1b5ff66 py: Add note about -fno-crossjumping when compiling vm.c. 2014-12-29 00:07:47 +00:00
Damien George
96e22154d7 docs: Bump version to 1.3.8.
Should have done it before tagging...
2014-12-29 00:04:59 +00:00
334 changed files with 6113 additions and 3376 deletions

View File

@@ -7,15 +7,16 @@ before_script:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
- sudo apt-get update -qq
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system mingw32
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-multilib gcc-arm-none-eabi qemu-system mingw32
# For teensy build
- sudo apt-get install realpath
script:
- make -C minimal test
- make -C unix CC=gcc-4.7
- make -C unix-cpy CC=gcc-4.7
- make -C bare-arm
- make -C qemu-arm
- make -C qemu-arm test
- make -C stmhal
- make -C stmhal -B MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1
- make -C stmhal BOARD=STM32F4DISC
@@ -27,3 +28,4 @@ script:
after_failure:
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
- (grep "FAIL" qemu-arm/build/console.out)

View File

@@ -10,7 +10,6 @@ CROSS_COMPILE = arm-none-eabi-
INC = -I.
INC += -I..
INC += -I$(PY_SRC)
INC += -I$(BUILD)
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion

View File

@@ -2,19 +2,12 @@
#include <stdio.h>
#include <string.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "repl.h"
#include "pfenv.h"
#include "py/nlr.h"
#include "py/parsehelper.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/pfenv.h"
void do_str(const char *src) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);

View File

@@ -6,6 +6,8 @@
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (0)

View File

@@ -60,7 +60,7 @@ copyright = '2014, Damien P. George'
# The short X.Y version.
version = '1.3'
# The full version, including alpha/beta/rc tags.
release = '1.3.7'
release = '1.3.9'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -39,6 +39,7 @@ it will fallback to loading the built-in ``ujson`` module.
:maxdepth: 1
ubinascii.rst
uctypes.rst
uhashlib.rst
uheapq.rst
ujson.rst

View File

@@ -53,7 +53,7 @@ Methods
Generate a triangle wave. The value on the DAC output changes at
the given frequency, and the frequence of the repeating triangle wave
itself is 256 (or 1024, need to check) times smaller.
itself is 2048 times smaller.
.. method:: dac.write(value)

View File

@@ -1,15 +1,37 @@
.. _pyb.Servo:
class Servo -- 3-wire hobby servo driver
========================================
Servo controls standard hobby servos with 3-wires (ground, power, signal).
Servo objects control standard hobby servo motors with 3-wires (ground, power,
signal). There are 4 positions on the pyboard where these motors can be plugged
in: pins X1 through X4 are the signal pins, and next to them are 4 sets of power
and ground pins.
Example usage::
import pyb
s1 = pyb.Servo(1) # create a servo object on position X1
s2 = pyb.Servo(2) # create a servo object on position X2
s1.angle(45) # move servo 1 to 45 degrees
s2.angle(0) # move servo 2 to 0 degrees
# move servo1 and servo2 synchronously, taking 1500ms
s1.angle(-60, 1500)
s2.angle(30, 1500)
.. note:: The Servo objects use Timer(5) to produce the PWM output. You can
use Timer(5) for Servo control, or your own purposes, but not both at the
same time.
Constructors
------------
.. class:: pyb.Servo(id)
Create a servo object. ``id`` is 1-4.
Create a servo object. ``id`` is 1-4, and corresponds to pins X1 through X4.
Methods
@@ -17,22 +39,41 @@ Methods
.. method:: servo.angle([angle, time=0])
Get or set the angle of the servo.
If no arguments are given, this function returns the current angle.
If arguments are given, this function sets the angle of the servo:
- ``angle`` is the angle to move to in degrees.
- ``time`` is the number of milliseconds to take to get to the specified angle.
.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
Get or set the calibration of the servo timing.
.. method:: servo.pulse_width([value])
Get or set the pulse width in milliseconds.
- ``time`` is the number of milliseconds to take to get to the specified
angle. If omitted, then the servo moves as quickly as possible to its
new position.
.. method:: servo.speed([speed, time=0])
Get or set the speed of a continuous rotation servo.
- ``speed`` is the speed to move to change to, between -100 and 100.
- ``time`` is the number of milliseconds to take to get to the specified speed.
If no arguments are given, this function returns the current speed.
If arguments are given, this function sets the speed of the servo:
- ``speed`` is the speed to change to, between -100 and 100.
- ``time`` is the number of milliseconds to take to get to the specified
speed. If omitted, then the servo accelerates as quickly as possible.
.. method:: servo.pulse_width([value])
If no arguments are given, this function returns the current raw pulse-width
value.
If an argument is given, this function sets the raw pulse-width value.
.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
If no arguments are given, this function returns the current calibration
data, as a 5-tuple.
If arguments are given, this function sets the timing calibration:
- ``pulse_min`` is the minimum allowed pulse width.
- ``pulse_max`` is the maximum allowed pulse width.
- ``pulse_centre`` is the pulse width corresponding to the centre/zero position.
- ``pulse_angle_90`` is the pulse width corresponding to 90 degrees.
- ``pulse_speed_100`` is the pulse width corresponding to a speed of 100.

View File

@@ -98,6 +98,7 @@ Power related functions
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
@@ -112,6 +113,9 @@ Power related functions
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,

138
docs/library/uctypes.rst Normal file
View File

@@ -0,0 +1,138 @@
:mod:`uctypes` -- access C structures
=====================================
.. module:: uctypes
:synopsis: access C structures
This module implements "foreign data interface" for MicroPython. The idea
behind it is similar to CPython's ``ctypes`` modules, but actual API is
different, steamlined and optimized for small size.
Defining structure layout
-------------------------
Structure layout is defined by a "descriptor" - a Python dictionary which
encodes field names as keys and other properties required to access them as
an associated values. Currently, uctypes requires explicit specification of
offsets for each field. Offset are given in bytes from structure start.
Following are encoding examples for various field types:
Scalar types::
"field_name": uctypes.UINT32 | 0
in other words, value is scalar type identifier ORed with field offset
(in bytes) from the start of the structure.
Recursive structures::
"sub": (2, {
"b0": uctypes.UINT8 | 0,
"b1": uctypes.UINT8 | 1,
})
i.e. value is a 2-tuple, first element of which is offset, and second is
a structure descriptor dictionary (note: offsets in recursive descriptors
are relative to a structure it defines).
Arrays of primitive types::
"arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
with offset, and second is scalar element type ORed number of elements
in array.
Arrays of aggregate types::
"arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
with offset, second is a number of elements in array, and third is
descriptor of element type.
Pointer to a primitive type::
"ptr": (uctypes.PTR | 0, uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, and second is scalar element type.
Pointer to aggregate type::
"ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, second is descriptor of type pointed to.
Bitfields::
"bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN,
i.e. value is type of scalar value containing given bitfield (typenames are
similar to scalar types, but prefixes with "BF"), ORed with offset for
scalar value containing the bitfield, and further ORed with values for
bit offset and bit length of the bitfield within scalar value, shifted by
BF_POS and BF_LEN positions, respectively. Bitfield position is counted
from the least significant bit, and is the number of right-most bit of a
field (in other words, it's a number of bits a scalar needs to be shifted
right to extra the bitfield).
In the example above, first UINT16 value will be extracted at offset 0
(this detail may be important when accessing hardware registers, where
particular access size and alignment are required), and then bitfield
whose rightmost bit is least-significant bit of this UINT16, and length
is 8 bits, will be extracted - effectively, this will access
least-significant byte of UINT16.
Note that bitfield operations are independent of target byte endianness,
in particular, example above will access least-significant byte of UINT16
in both little- and big-endian structures. But it depends on the least
significant bit being numbered 0. Some targets may use different
numbering in their native ABI, but ``uctypes`` always uses normalized
numbering described above.
Module contents
---------------
.. class:: struct(descriptor, layout_type)
Create a "foreign data structure" object based on its descriptor (encoded
as a dictionary) and layout type.
.. data:: LITTLE_ENDIAN
Little-endian packed structure. (Packed means that every field occupies
exactly many bytes as defined in the descriptor, i.e. alignment is 1).
.. data:: BIG_ENDIAN
Big-endian packed structure.
.. data:: NATIVE
Native structure - with data endianness and alignment conforming to
the target ABI.
(to be continued)
Structure objects
-----------------
Structure objects allow accessing individual fields using standard dot
notation: ``my_struct.field1``. If a field is of scalar type, getting
it will produce primitive value (Python integer or float) corresponding
to value contained in a field. Scalar field can also be assigned to.
If a field is an array, its individual elements can be accessed with
standard subscript operator - both read and assigned to.
If a field is a pointer, it can be dereferenced using ``[0]`` syntax
(corresponding to C ``*`` operator, though ``[0]`` works in C too).
Subscripting pointer with other integer values but 0 are supported too,
with the same semantics as in C.
Summing up, accessing structure fields generally follows C syntax,
except for pointer derefence, you need to use ``[0]`` operator instead
of ``*``.

View File

@@ -48,6 +48,18 @@ See :ref:`pyb.Pin <pyb.Pin>`. ::
p_in = Pin('X2', Pin.IN, Pin.PULL_UP)
p_in.value() # get value, 0 or 1
Servo control
-------------
See :ref:`pyb.Servo <pyb.Servo>`. ::
from pyb import Servo
s1 = Servo(1) # servo on position 1 (X1, VIN, GND)
s1.angle(45) # move to 45 degrees
s1.angle(-60, 1500) # move to -60 degrees in 1500ms
s1.speed(50) # for continuous rotation servos
External interrupts
-------------------

View File

@@ -55,9 +55,13 @@ For example::
You can also play WAV files using the Python ``wave`` module. You can get
the wave module `here <http://micropython.org/resources/examples/wave.py>`_ and you will also need
the chunk module available `here <http://micropython.org/resources/examples/chunk.py>`_. Put these
on your pyboard (either on the flash or the SD card in the top-level
directory). You will need an 8-bit WAV file to play, such as
`this one <http://micropython.org/resources/examples/test.wav>`_. Then you can do::
on your pyboard (either on the flash or the SD card in the top-level directory). You will need an
8-bit WAV file to play, such as `this one <http://micropython.org/resources/examples/test.wav>`_,
or to convert any file you have with the command::
avconv -i original.wav -ar 22050 -codec pcm_u8 test.wav
Then you can do::
>>> import wave
>>> from pyb import DAC

View File

@@ -23,6 +23,9 @@ then select the option to find the driver manually (don't use Windows auto updat
navigate to the pyboard's USB drive, and select that. It should then install.
After installing, go back to the Device Manager to find the installed pyboard,
and see which COM port it is (eg COM4).
More comprehensive instructions can be found in the
`Guide for pyboard on Windows (PDF) <http://micropython.org/resources/Micro-Python-Windows-setup.pdf>`_.
Please consult this guide if you are having problems installing the driver.
You now need to run your terminal program. You can use HyperTerminal if you
have it installed, or download the free program PuTTY:

View File

@@ -34,13 +34,9 @@
#include <string.h>
#include "stm32f4xx_hal.h"
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "pin.h"
#include "led.h"
#include "extint.h"
@@ -177,7 +173,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler)
CS_HIGH();
// register EXTI
extint_register((mp_obj_t)PIN_IRQ, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t)&irq_callback_obj, true, NULL);
extint_register((mp_obj_t)PIN_IRQ, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t)&irq_callback_obj, true);
extint_enable(PIN_IRQ->pin);
DEBUG_printf("SpiOpen finished; IRQ.pin=%d IRQ_LINE=%d\n", PIN_IRQ->pin, PIN_IRQ->pin);

View File

@@ -11,8 +11,9 @@ CROSS_COMPILE = xtensa-lx106-elf-
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
INC = -I.
INC += -I$(PY_SRC)
INC += -I..
INC += -I../stmhal
INC += -I../lib/mp-readline
INC += -I$(BUILD)
INC += -I$(ESP_SDK)/include
@@ -52,7 +53,10 @@ STM_SRC_C = $(addprefix stmhal/,\
printf.c \
string0.c \
pyexec.c \
readline.c \
)
LIB_SRC_C = $(addprefix lib/,\
mp-readline/readline.c \
)
SRC_S = \
@@ -63,6 +67,7 @@ OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
#OBJ += $(BUILD)/pins_$(BOARD).o
all: $(BUILD)/firmware-combined.bin

View File

@@ -40,4 +40,7 @@ void HAL_Delay(uint32_t Delay);
void mp_hal_set_interrupt_char(int c);
uint32_t mp_hal_get_cpu_freq(void);
#define UART_TASK_ID 0
void uart_task_init();
#endif // _INCLUDED_MPHAL_H_

View File

@@ -25,13 +25,8 @@
*/
#include <stdio.h>
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "gc.h"
#include "py/gc.h"
#include "gccollect.h"
STATIC uint32_t stack_end;

View File

@@ -27,27 +27,24 @@
#include <stdio.h>
#include <string.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "gc.h"
#include "py/nlr.h"
#include "py/parsehelper.h"
#include "py/compile.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "py/gc.h"
#include "pyexec.h"
#include "gccollect.h"
#include MICROPY_HAL_H
STATIC char heap[16384];
void user_init(void) {
soft_reset:
//mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 1024);
mp_stack_set_limit(10240);
mp_hal_init();
gc_init(&_heap_start, &_heap_end);
gc_init(heap, heap + sizeof(heap));
gc_collect_init();
mp_init();
mp_obj_list_init(mp_sys_path, 0);
@@ -55,6 +52,12 @@ soft_reset:
printf("\n");
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_friendly_repl_init();
uart_task_init();
return;
goto soft_reset;
#else
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
if (pyexec_raw_repl() != 0) {
@@ -68,6 +71,7 @@ soft_reset:
}
goto soft_reset;
#endif
}
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {

View File

@@ -24,19 +24,16 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "gc.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/gc.h"
#include "gccollect.h"
#include "pyexec.h"
#include "pybstdio.h"
#include MICROPY_HAL_H
#include "user_interface.h"
STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) {
// print info about memory
@@ -140,6 +137,12 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
STATIC mp_obj_t pyb_hard_reset(void) {
system_restart();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_hard_reset_obj, pyb_hard_reset);
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
@@ -153,6 +156,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj },
};
STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);

View File

@@ -9,6 +9,8 @@
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_STACK_CHECK (0)
#define MICROPY_REPL_EVENT_DRIVEN (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (1)
@@ -61,6 +63,11 @@ extern const struct _mp_obj_module_t pyb_module;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
#define MP_STATE_PORT MP_STATE_VM
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8];
// We need to provide a declaration/definition of alloca()
#include <alloca.h>

View File

@@ -25,16 +25,11 @@
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "misc.h"
#include "obj.h"
#include "stream.h"
#include "py/obj.h"
#include "py/stream.h"
#include "pybstdio.h"
#include MICROPY_HAL_H

View File

@@ -39,3 +39,4 @@ Q(elapsed_micros)
Q(delay)
Q(udelay)
Q(sync)
Q(hard_reset)

View File

@@ -16,6 +16,8 @@
#include "uart_register.h"
#include "etshal.h"
#include "c_types.h"
#include "user_interface.h"
#include "esp_mphal.h"
#define RX_BUF_SIZE (256)
@@ -27,6 +29,8 @@ static uint16_t rx_buf_in;
static uint16_t rx_buf_out;
static uint8_t rx_buf[RX_BUF_SIZE];
static os_event_t uart_evt_queue[16];
static void uart0_rx_intr_handler(void *para);
/******************************************************************************
@@ -148,11 +152,15 @@ static void uart0_rx_intr_handler(void *para) {
read_chars:
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
system_os_post(UART_TASK_ID, 0, RcvChar);
#else
uint16_t rx_buf_in_next = (rx_buf_in + 1) % RX_BUF_SIZE;
if (rx_buf_in_next != rx_buf_out) {
rx_buf[rx_buf_in] = RcvChar;
rx_buf_in = rx_buf_in_next;
}
#endif
}
}
}
@@ -189,3 +197,15 @@ void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
void ICACHE_FLASH_ATTR uart_reattach() {
uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
}
// Task-based UART interface
int pyexec_friendly_repl_process_char(int c);
void uart_task_handler(os_event_t *evt) {
pyexec_friendly_repl_process_char(evt->par);
}
void uart_task_init() {
system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
}

View File

@@ -28,22 +28,20 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "binary.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/binary.h"
#if MICROPY_PY_UBINASCII
STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args;
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
byte *in = bufinfo.buf, *out;
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, bufinfo.len * 2, &out);
vstr_t vstr;
vstr_init_len(&vstr, bufinfo.len * 2);
byte *in = bufinfo.buf, *out = (byte*)vstr.buf;
for (mp_uint_t i = bufinfo.len; i--;) {
byte d = (*in >> 4);
if (d > 9) {
@@ -56,7 +54,7 @@ STATIC mp_obj_t mod_binascii_hexlify(mp_uint_t n_args, const mp_obj_t *args) {
}
*out++ = d + '0';
}
return mp_obj_str_builder_end(o);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);

View File

@@ -27,14 +27,11 @@
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "objtuple.h"
#include "binary.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/objtuple.h"
#include "py/binary.h"
#if MICROPY_PY_UCTYPES
@@ -120,11 +117,12 @@ typedef struct _mp_obj_uctypes_struct_t {
uint32_t flags;
} mp_obj_uctypes_struct_t;
STATIC NORETURN void syntax_error() {
STATIC NORETURN void syntax_error(void) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "syntax error in uctypes descriptor"));
}
STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
(void)n_kw;
if (n_args < 2 || n_args > 3) {
syntax_error();
}
@@ -140,6 +138,7 @@ STATIC mp_obj_t uctypes_struct_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_u
}
STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_uctypes_struct_t *self = self_in;
const char *typen = "unk";
if (MP_OBJ_IS_TYPE(self->desc, &mp_type_dict)) {

View File

@@ -27,12 +27,8 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/runtime.h"
#if MICROPY_PY_UHASHLIB
@@ -67,14 +63,15 @@ MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = self_in;
byte *hash;
mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, SHA256_BLOCK_SIZE, &hash);
sha256_final((SHA256_CTX*)self->state, hash);
return mp_obj_str_builder_end(o);
vstr_t vstr;
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
sha256_final((SHA256_CTX*)self->state, (byte*)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
STATIC mp_obj_t hash_hexdigest(mp_obj_t self_in) {
(void)self_in;
mp_not_implemented("");
#if 0
mp_obj_hash_t *self = self_in;

View File

@@ -26,14 +26,10 @@
#include <unistd.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "objlist.h"
#include "runtime0.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/objlist.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#if MICROPY_PY_UHEAPQ

View File

@@ -28,14 +28,10 @@
#include <unistd.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "nlr.h"
#include "qstr.h"
#include "obj.h"
#include "objlist.h"
#include "parsenum.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/objlist.h"
#include "py/parsenum.h"
#include "py/runtime.h"
#if MICROPY_PY_UJSON
@@ -85,6 +81,9 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
case ',':
case ':':
case ' ':
case '\t':
case '\n':
case '\r':
s += 1;
goto cont;
case 'n':

View File

@@ -28,13 +28,9 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "binary.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/binary.h"
#if MICROPY_PY_URE
@@ -56,6 +52,7 @@ typedef struct _mp_obj_match_t {
STATIC void match_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_match_t *self = self_in;
print(env, "<match num=%d @%p>", self->num_matches);
}
@@ -86,11 +83,13 @@ STATIC const mp_obj_type_t match_type = {
};
STATIC void re_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_re_t *self = self_in;
print(env, "<re %p>", self);
}
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
(void)n_args;
mp_obj_re_t *self = args[0];
Subject subj;
mp_uint_t len;
@@ -196,6 +195,7 @@ STATIC mp_obj_t mod_re_compile(uint n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
(void)n_args;
mp_obj_re_t *self = mod_re_compile(1, args);
const mp_obj_t args2[] = {self, args[1]};

View File

@@ -31,12 +31,8 @@
#include <sys/time.h>
#include <math.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "nlr.h"
#include "obj.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/runtime.h"
#if MICROPY_PY_UZLIB
@@ -59,6 +55,7 @@ STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) {
}
STATIC mp_obj_t mod_uzlib_decompress(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args;
mp_obj_t data = args[0];
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);

View File

@@ -49,6 +49,11 @@ double __attribute__((pcs("aapcs"))) __aeabi_i2d(int32_t x) {
return (float)x;
}
// TODO
long long __attribute__((pcs("aapcs"))) __aeabi_f2lz(float x) {
return (long)x;
}
double __attribute__((pcs("aapcs"))) __aeabi_f2d(float x) {
float_s_t fx={0};
double_s_t dx={0};
@@ -117,8 +122,6 @@ float tgammaf(float x) { return 0.0; }
float lgammaf(float x) { return 0.0; }
float erff(float x) { return 0.0; }
float erfcf(float x) { return 0.0; }
float modff(float x, float *y) { return 0.0; }
float frexpf(float x, int *exp) { return 0.0; }
float ldexpf(float x, int exp) { return 0.0; }
/*****************************************************************************/

70
lib/libm/sf_frexp.c Normal file
View File

@@ -0,0 +1,70 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/math
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* sf_frexp.c -- float version of s_frexp.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
static const float
#else
static float
#endif
two25 = 3.3554432000e+07; /* 0x4c000000 */
#ifdef __STDC__
float frexpf(float x, int *eptr)
#else
float frexpf(x, eptr)
float x; int *eptr;
#endif
{
__int32_t hx, ix;
GET_FLOAT_WORD(hx,x);
ix = 0x7fffffff&hx;
*eptr = 0;
if(!FLT_UWORD_IS_FINITE(ix)||FLT_UWORD_IS_ZERO(ix)) return x; /* 0,inf,nan */
if (FLT_UWORD_IS_SUBNORMAL(ix)) { /* subnormal */
x *= two25;
GET_FLOAT_WORD(hx,x);
ix = hx&0x7fffffff;
*eptr = -25;
}
*eptr += (ix>>23)-126;
hx = (hx&0x807fffff)|0x3f000000;
SET_FLOAT_WORD(x,hx);
return x;
}
#ifdef _DOUBLE_IS_32BITS
#ifdef __STDC__
double frexp(double x, int *eptr)
#else
double frexp(x, eptr)
double x; int *eptr;
#endif
{
return (double) frexpf((float) x, eptr);
}
#endif /* defined(_DOUBLE_IS_32BITS) */

82
lib/libm/sf_modf.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* These math functions are taken from newlib-nano-2, the newlib/libm/common
* directory, available from https://github.com/32bitmicro/newlib-nano-2.
*
* Appropriate copyright headers are reproduced below.
*/
/* sf_modf.c -- float version of s_modf.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#include "fdlibm.h"
#ifdef __STDC__
static const float one = 1.0;
#else
static float one = 1.0;
#endif
#ifdef __STDC__
float modff(float x, float *iptr)
#else
float modff(x, iptr)
float x,*iptr;
#endif
{
__int32_t i0,j0;
__uint32_t i;
GET_FLOAT_WORD(i0,x);
j0 = ((i0>>23)&0xff)-0x7f; /* exponent of x */
if(j0<23) { /* integer part in x */
if(j0<0) { /* |x|<1 */
SET_FLOAT_WORD(*iptr,i0&0x80000000); /* *iptr = +-0 */
return x;
} else {
i = (0x007fffff)>>j0;
if((i0&i)==0) { /* x is integral */
__uint32_t ix;
*iptr = x;
GET_FLOAT_WORD(ix,x);
SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
return x;
} else {
SET_FLOAT_WORD(*iptr,i0&(~i));
return x - *iptr;
}
}
} else { /* no fraction part */
__uint32_t ix;
*iptr = x*one;
GET_FLOAT_WORD(ix,x);
SET_FLOAT_WORD(x,ix&0x80000000); /* return +-0 */
return x;
}
}
#ifdef _DOUBLE_IS_32BITS
#ifdef __STDC__
double modf(double x, double *iptr)
#else
double modf(x, iptr)
double x,*iptr;
#endif
{
return (double) modff((float) x, (float *) iptr);
}
#endif /* defined(_DOUBLE_IS_32BITS) */

276
lib/mp-readline/readline.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include "py/mpstate.h"
#include "readline.h"
#include "pybstdio.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
#define DEBUG_printf printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
#define READLINE_HIST_SIZE (MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)))
enum { ESEQ_NONE, ESEQ_ESC, ESEQ_ESC_BRACKET, ESEQ_ESC_BRACKET_DIGIT, ESEQ_ESC_O };
void readline_init0(void) {
memset(MP_STATE_PORT(readline_hist), 0, READLINE_HIST_SIZE * sizeof(const char*));
}
STATIC char *str_dup_maybe(const char *str) {
uint32_t len = strlen(str);
char *s2 = m_new_maybe(char, len + 1);
if (s2 == NULL) {
return NULL;
}
memcpy(s2, str, len + 1);
return s2;
}
typedef struct _readline_t {
vstr_t *line;
int orig_line_len;
int escape_seq;
int hist_cur;
int cursor_pos;
char escape_seq_buf[1];
} readline_t;
readline_t rl;
int readline_process_char(int c) {
int last_line_len = rl.line->len;
int redraw_step_back = 0;
bool redraw_from_cursor = false;
int redraw_step_forward = 0;
if (rl.escape_seq == ESEQ_NONE) {
if (CHAR_CTRL_A <= c && c <= CHAR_CTRL_D && vstr_len(rl.line) == rl.orig_line_len) {
// control character with empty line
return c;
} else if (c == CHAR_CTRL_A) {
// CTRL-A with non-empty line is go-to-start-of-line
goto home_key;
} else if (c == CHAR_CTRL_C) {
// CTRL-C with non-empty line is cancel
return c;
} else if (c == CHAR_CTRL_E) {
// CTRL-E is go-to-end-of-line
goto end_key;
} else if (c == '\r') {
// newline
stdout_tx_str("\r\n");
if (rl.line->len > rl.orig_line_len && (MP_STATE_PORT(readline_hist)[0] == NULL || strcmp(MP_STATE_PORT(readline_hist)[0], rl.line->buf + rl.orig_line_len) != 0)) {
// a line which is not empty and different from the last one
// so update the history
char *most_recent_hist = str_dup_maybe(rl.line->buf + rl.orig_line_len);
if (most_recent_hist != NULL) {
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];
}
MP_STATE_PORT(readline_hist)[0] = most_recent_hist;
}
}
return 0;
} else if (c == 27) {
// escape sequence
rl.escape_seq = ESEQ_ESC;
} else if (c == 8 || c == 127) {
// backspace/delete
if (rl.cursor_pos > rl.orig_line_len) {
vstr_cut_out_bytes(rl.line, rl.cursor_pos - 1, 1);
// set redraw parameters
redraw_step_back = 1;
redraw_from_cursor = true;
}
} else if (32 <= c && c <= 126) {
// printable character
vstr_ins_char(rl.line, rl.cursor_pos, c);
// set redraw parameters
redraw_from_cursor = true;
redraw_step_forward = 1;
}
} else if (rl.escape_seq == ESEQ_ESC) {
switch (c) {
case '[':
rl.escape_seq = ESEQ_ESC_BRACKET;
break;
case 'O':
rl.escape_seq = ESEQ_ESC_O;
break;
default:
DEBUG_printf("(ESC %d)", c);
rl.escape_seq = ESEQ_NONE;
}
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
if ('0' <= c && c <= '9') {
rl.escape_seq = ESEQ_ESC_BRACKET_DIGIT;
rl.escape_seq_buf[0] = c;
} else {
rl.escape_seq = ESEQ_NONE;
if (c == 'A') {
// up arrow
if (rl.hist_cur + 1 < READLINE_HIST_SIZE && MP_STATE_PORT(readline_hist)[rl.hist_cur + 1] != NULL) {
// increase hist num
rl.hist_cur += 1;
// set line to history
rl.line->len = rl.orig_line_len;
vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);
// set redraw parameters
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
redraw_from_cursor = true;
redraw_step_forward = rl.line->len - rl.orig_line_len;
}
} else if (c == 'B') {
// down arrow
if (rl.hist_cur >= 0) {
// decrease hist num
rl.hist_cur -= 1;
// set line to history
vstr_cut_tail_bytes(rl.line, rl.line->len - rl.orig_line_len);
if (rl.hist_cur >= 0) {
vstr_add_str(rl.line, MP_STATE_PORT(readline_hist)[rl.hist_cur]);
}
// set redraw parameters
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
redraw_from_cursor = true;
redraw_step_forward = rl.line->len - rl.orig_line_len;
}
} else if (c == 'C') {
// right arrow
if (rl.cursor_pos < rl.line->len) {
redraw_step_forward = 1;
}
} else if (c == 'D') {
// left arrow
if (rl.cursor_pos > rl.orig_line_len) {
redraw_step_back = 1;
}
} else if (c == 'H') {
// home
goto home_key;
} else if (c == 'F') {
// end
goto end_key;
} else {
DEBUG_printf("(ESC [ %d)", c);
}
}
} else if (rl.escape_seq == ESEQ_ESC_BRACKET_DIGIT) {
if (c == '~') {
if (rl.escape_seq_buf[0] == '1' || rl.escape_seq_buf[0] == '7') {
home_key:
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
} else if (rl.escape_seq_buf[0] == '4' || rl.escape_seq_buf[0] == '8') {
end_key:
redraw_step_forward = rl.line->len - rl.cursor_pos;
} else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
}
} else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
}
rl.escape_seq = ESEQ_NONE;
} else if (rl.escape_seq == ESEQ_ESC_O) {
switch (c) {
case 'H':
goto home_key;
case 'F':
goto end_key;
default:
DEBUG_printf("(ESC O %d)", c);
rl.escape_seq = ESEQ_NONE;
}
} else {
rl.escape_seq = ESEQ_NONE;
}
// redraw command prompt, efficiently
// TODO we can probably use some more sophisticated VT100 commands here
if (redraw_step_back > 0) {
for (int i = 0; i < redraw_step_back; i++) {
stdout_tx_str("\b");
}
rl.cursor_pos -= redraw_step_back;
}
if (redraw_from_cursor) {
if (rl.line->len < last_line_len) {
// erase old chars
for (int i = rl.cursor_pos; i < last_line_len; i++) {
stdout_tx_str(" ");
}
// step back
for (int i = rl.cursor_pos; i < last_line_len; i++) {
stdout_tx_str("\b");
}
}
// draw new chars
stdout_tx_strn(rl.line->buf + rl.cursor_pos, rl.line->len - rl.cursor_pos);
// move cursor forward if needed (already moved forward by length of line, so move it back)
for (int i = rl.cursor_pos + redraw_step_forward; i < rl.line->len; i++) {
stdout_tx_str("\b");
}
rl.cursor_pos += redraw_step_forward;
} else if (redraw_step_forward > 0) {
// draw over old chars to move cursor forwards
stdout_tx_strn(rl.line->buf + rl.cursor_pos, redraw_step_forward);
rl.cursor_pos += redraw_step_forward;
}
return -1;
}
void readline_note_newline(void) {
rl.orig_line_len = rl.line->len;
rl.cursor_pos = rl.orig_line_len;
}
void readline_init(vstr_t *line) {
rl.line = line;
rl.orig_line_len = line->len;
rl.escape_seq = ESEQ_NONE;
rl.escape_seq_buf[0] = 0;
rl.hist_cur = -1;
rl.cursor_pos = rl.orig_line_len;
}
int readline(vstr_t *line, const char *prompt) {
stdout_tx_str(prompt);
readline_init(line);
for (;;) {
int c = stdin_rx_chr();
int r = readline_process_char(c);
if (r >= 0) {
return r;
}
}
}

View File

@@ -32,3 +32,7 @@
void readline_init0(void);
int readline(vstr_t *line, const char *prompt);
void readline_init(vstr_t *line);
void readline_note_newline(void);
int readline_process_char(int c);

77
minimal/Makefile Normal file
View File

@@ -0,0 +1,77 @@
include ../py/mkenv.mk
CROSS = 0
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include ../py/py.mk
ifeq ($(CROSS), 1)
CROSS_COMPILE = arm-none-eabi-
endif
INC = -I.
INC += -I..
INC += -I../lib/mp-readline
INC += -I../stmhal
INC += -I$(BUILD)
ifeq ($(CROSS), 1)
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion
CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
else
CFLAGS = -m32 $(INC) -Wall -Werror -ansi -std=gnu99 $(COPT)
endif
#Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -Os -DNDEBUG
endif
ifeq ($(CROSS), 1)
LDFLAGS = -nostdlib -T stm32f405.ld -Map=$@.map --cref
else
LD = gcc
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref
endif
LIBS =
SRC_C = \
main.c \
uart_core.c \
uart_extra.c \
stmhal/printf.c \
stmhal/string0.c \
stmhal/pyexec.c \
lib/mp-readline/readline.c \
SRC_S = \
# startup_stm32f40xx.s \
gchelper.s \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
$(Q)$(SIZE) $@
# Run emulation build on a POSIX system with suitable terminal settings
run:
stty raw opost -echo
build/firmware.elf
@echo Resetting terminal...
# This sleep is useful to spot segfaults
sleep 1
reset
test: $(BUILD)/firmware.elf
$(Q)/bin/echo -e "print('hello world!', list(x+1 for x in range(10)), end='eol\\\\n')\\r\\n\\x04" | $(BUILD)/firmware.elf | tail -n2 | grep "^hello world! \\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\]eol"
include ../py/mkrules.mk

118
minimal/main.c Normal file
View File

@@ -0,0 +1,118 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "py/nlr.h"
#include "py/parsehelper.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/pfenv.h"
#include "py/gc.h"
#include "pyexec.h"
#include "pybstdio.h"
void do_str(const char *src) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
return;
}
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind);
if (pn == MP_PARSE_NODE_NULL) {
// parse error
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
return;
}
// parse okay
qstr source_name = lex->source_name;
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
if (mp_obj_is_exception_instance(module_fun)) {
// compile error
mp_obj_print_exception(printf_wrapper, NULL, module_fun);
return;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_0(module_fun);
nlr_pop();
} else {
// uncaught exception
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
}
}
static char *stack_top;
static char heap[2048];
int main(int argc, char **argv) {
int stack_dummy;
stack_top = (char*)&stack_dummy;
#if MICROPY_ENABLE_GC
gc_init(heap, heap + sizeof(heap));
#endif
mp_init();
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_friendly_repl_init();
for (;;) {
int c = stdin_rx_chr();
if (pyexec_friendly_repl_process_char(c)) {
break;
}
}
#else
pyexec_friendly_repl();
#endif
//do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')");
mp_deinit();
return 0;
}
void gc_collect(void) {
// WARNING: This gc_collect implementation doesn't try to get root
// pointers from CPU registers, and thus may function incorrectly.
void *dummy;
gc_collect_start();
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
gc_collect_end();
gc_dump_info();
}
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
return NULL;
}
mp_import_stat_t mp_import_stat(const char *path) {
return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
void nlr_jump_fail(void *val) {
}
void NORETURN __fatal_error(const char *msg) {
while (1);
}
#ifndef NDEBUG
void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
__fatal_error("Assertion failed");
}
#endif
#if !MICROPY_MIN_USE_STDOUT
void _start(void) {main(0, NULL);}
#endif

81
minimal/mpconfigport.h Normal file
View File

@@ -0,0 +1,81 @@
#include <stdint.h>
// options to control how Micro Python is built
#define MICROPY_ALLOC_PATH_MAX (256)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_COMP_MODULE_CONST (0)
#define MICROPY_COMP_CONST (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (0)
#define MICROPY_ENABLE_DOC_STRING (0)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
#define MICROPY_PY_BUILTINS_FROZENSET (0)
#define MICROPY_PY_BUILTINS_SET (0)
#define MICROPY_PY_BUILTINS_SLICE (0)
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (0)
#define MICROPY_PY_ARRAY (0)
#define MICROPY_PY_COLLECTIONS (0)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (0)
#define MICROPY_PY_STRUCT (0)
#define MICROPY_PY_SYS (0)
#define MICROPY_MODULE_FROZEN (0)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
// type definitions for the specific machine
#define BYTES_PER_WORD (4)
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
// This port is intended to be 32-bit, but unfortunately, int32_t for
// different targets may be defined in different ways - either as int
// or as long. This requires different printf formatting specifiers
// to print such value. So, we avoid int32_t and use int directly.
#define UINT_FMT "%u"
#define INT_FMT "%d"
typedef int mp_int_t; // must be pointer size
typedef unsigned mp_uint_t; // must be pointer size
typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
// extra built in names to add to the global namespace
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
#define HAL_GetTick() 0
static inline void mp_hal_set_interrupt_char(char c) {}
#define MICROPY_HW_BOARD_NAME "minimal"
#define MICROPY_HW_MCU_NAME "unknown-cpu"
#ifdef __linux__
#define MICROPY_MIN_USE_STDOUT (1)
#endif
#define MP_STATE_PORT MP_STATE_VM
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8];

1
minimal/qstrdefsport.h Normal file
View File

@@ -0,0 +1 @@
// qstrs specific to this port

117
minimal/stm32f405.ld Normal file
View File

@@ -0,0 +1,117 @@
/*
GNU linker script for STM32F405
*/
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000 /* entire flash, 1 MiB */
FLASH_ISR (rx) : ORIGIN = 0x08000000, LENGTH = 0x004000 /* sector 0, 16 KiB */
FLASH_TEXT (rx) : ORIGIN = 0x08020000, LENGTH = 0x080000 /* sectors 5,6,7,8, 4*128KiB = 512 KiB (could increase it more) */
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 0x010000 /* 64 KiB */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* 128 KiB */
}
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* RAM extents for the garbage collector */
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
_heap_end = 0x2001c000; /* tunable */
/* define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH_ISR
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
/* *(.glue_7) */ /* glue arm to thumb code */
/* *(.glue_7t) */ /* glue thumb to arm code */
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH_TEXT
/*
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >FLASH
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
*/
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM. */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
_ram_start = .; /* create a global symbol at ram start for garbage collector */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
} >RAM
/* this is to define the start of the heap, and make sure we have a minimum size */
.heap :
{
. = ALIGN(4);
_heap_start = .; /* define a global symbol at heap start */
} >RAM
/* this just checks there is enough RAM for the stack */
.stack :
{
. = ALIGN(4);
} >RAM
/* Remove information from the standard libraries */
/*
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
*/
.ARM.attributes 0 : { *(.ARM.attributes) }
}

24
minimal/uart_core.c Normal file
View File

@@ -0,0 +1,24 @@
#include <unistd.h>
#include "py/mpconfig.h"
/*
* Core UART functions to implement for a port
*/
// Receive single character
int stdin_rx_chr(void) {
unsigned char c = 0;
#if MICROPY_MIN_USE_STDOUT
int r = read(0, &c, 1);
(void)r;
#endif
return c;
}
// Send string of given length
void stdout_tx_strn(const char *str, mp_uint_t len) {
#if MICROPY_MIN_USE_STDOUT
int r = write(1, str, len);
(void)r;
#endif
}

26
minimal/uart_extra.c Normal file
View File

@@ -0,0 +1,26 @@
#include <string.h>
#include <unistd.h>
#include "py/mpconfig.h"
#include "pybstdio.h"
/*
* Extra UART functions
* These can be either optimized for a particular port, or reference,
* not very optimal implementation below can be used.
*/
// Send "cooked" string of length, where every occurance of
// LF character is replaced with CR LF.
void stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
while (len--) {
if (*str == '\n') {
stdout_tx_strn("\r", 1);
}
stdout_tx_strn(str++, 1);
}
}
// Send zero-terminated string
void stdout_tx_str(const char *str) {
stdout_tx_strn(str, strlen(str));
}

View File

@@ -27,23 +27,15 @@
#include <stdlib.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
STATIC NORETURN void terse_arg_mismatch(void) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch"));
}
#include "py/nlr.h"
#include "py/runtime.h"
void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp_uint_t n_args_max, bool takes_kw) {
// TODO maybe take the function name as an argument so we can print nicer error messages
if (n_kw && !takes_kw) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"function does not take keyword arguments"));
@@ -53,7 +45,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
if (n_args_min == n_args_max) {
if (n_args != n_args_min) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function takes %d positional arguments but %d were given",
@@ -63,7 +55,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
} else {
if (n_args < n_args_min) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function missing %d required positional arguments",
@@ -71,7 +63,7 @@ void mp_arg_check_num(mp_uint_t n_args, mp_uint_t n_kw, mp_uint_t n_args_min, mp
}
} else if (n_args > n_args_max) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function expected at most %d arguments, got %d",
@@ -92,15 +84,15 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
pos_found++;
given_arg = pos[i];
} else {
mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qstr), MP_MAP_LOOKUP);
mp_map_elem_t *kw = mp_map_lookup(kws, MP_OBJ_NEW_QSTR(allowed[i].qst), MP_MAP_LOOKUP);
if (kw == NULL) {
if (allowed[i].flags & MP_ARG_REQUIRED) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"'%s' argument required",
qstr_str(allowed[i].qstr)));
qstr_str(allowed[i].qst)));
}
}
out_vals[i] = allowed[i].defval;
@@ -123,7 +115,7 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
if (pos_found < n_pos) {
extra_positional:
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
// TODO better error message
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
@@ -132,7 +124,7 @@ void mp_arg_parse_all(mp_uint_t n_pos, const mp_obj_t *pos, mp_map_t *kws, mp_ui
}
if (kws_found < kws->used) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
terse_arg_mismatch();
mp_arg_error_terse_mismatch();
} else {
// TODO better error message
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
@@ -147,6 +139,12 @@ void mp_arg_parse_all_kw_array(mp_uint_t n_pos, mp_uint_t n_kw, const mp_obj_t *
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);
}
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER
NORETURN void mp_arg_error_terse_mismatch(void) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch"));
}
#endif
#if MICROPY_CPYTHON_COMPAT
NORETURN void mp_arg_error_unimpl_kw(void) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError,

View File

@@ -29,13 +29,13 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "asmarm.h"
#include "py/mpconfig.h"
// wrapper around everything in this file
#if MICROPY_EMIT_ARM
#include "py/asmarm.h"
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
struct _asm_arm_t {
@@ -70,20 +70,20 @@ void asm_arm_free(asm_arm_t *as, bool free_code) {
}
void asm_arm_start_pass(asm_arm_t *as, uint pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_ARM_PASS_COMPUTE) {
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
} else if (pass == ASM_ARM_PASS_EMIT) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
if (as->code_base == NULL) {
assert(0);
}
}
as->pass = pass;
as->code_offset = 0;
}
void asm_arm_end_pass(asm_arm_t *as) {
if (as->pass == ASM_ARM_PASS_COMPUTE) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
if(as->code_base == NULL) {
assert(0);
}
} else if(as->pass == ASM_ARM_PASS_EMIT) {
if (as->pass == ASM_ARM_PASS_EMIT) {
#ifdef __arm__
// flush I- and D-cache
asm volatile(

View File

@@ -24,6 +24,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_ASMARM_H__
#define __MICROPY_INCLUDED_PY_ASMARM_H__
#include "py/misc.h"
#define ASM_ARM_PASS_COMPUTE (1)
#define ASM_ARM_PASS_EMIT (2)
@@ -120,3 +124,4 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
void asm_arm_b_label(asm_arm_t *as, uint label);
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
#endif // __MICROPY_INCLUDED_PY_ASMARM_H__

View File

@@ -28,13 +28,13 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "asmthumb.h"
#include "py/mpconfig.h"
// wrapper around everything in this file
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
#include "py/asmthumb.h"
#define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0)
#define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0)
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
@@ -73,32 +73,21 @@ void asm_thumb_free(asm_thumb_t *as, bool free_code) {
}
void asm_thumb_start_pass(asm_thumb_t *as, uint pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_THUMB_PASS_COMPUTE) {
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
}
}
void asm_thumb_end_pass(asm_thumb_t *as) {
if (as->pass == ASM_THUMB_PASS_COMPUTE) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
if(as->code_base == NULL) {
} else if (pass == ASM_THUMB_PASS_EMIT) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
if (as->code_base == NULL) {
assert(0);
}
//printf("code_size: %u\n", as->code_size);
}
as->pass = pass;
as->code_offset = 0;
}
/*
// check labels are resolved
if (as->label != NULL)
{
int i;
for (i = 0; i < as->label->len; ++i)
if (g_array_index(as->label, Label, i).unresolved != NULL)
return false;
}
*/
void asm_thumb_end_pass(asm_thumb_t *as) {
// could check labels are resolved...
}
// all functions must go through this one to emit bytes

View File

@@ -23,6 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_ASMTHUMB_H__
#define __MICROPY_INCLUDED_PY_ASMTHUMB_H__
#include "py/misc.h"
#define ASM_THUMB_PASS_COMPUTE (1)
#define ASM_THUMB_PASS_EMIT (2)
@@ -200,3 +204,5 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num)
void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience ?
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ?
#endif // __MICROPY_INCLUDED_PY_ASMTHUMB_H__

View File

@@ -29,13 +29,12 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "py/mpconfig.h"
// wrapper around everything in this file
#if MICROPY_EMIT_X64
#include "asmx64.h"
#include "py/asmx64.h"
/* all offsets are measured in multiples of 8 bytes */
#define WORD_SIZE (8)
@@ -144,33 +143,23 @@ void asm_x64_free(asm_x64_t *as, bool free_code) {
}
void asm_x64_start_pass(asm_x64_t *as, uint pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_X64_PASS_COMPUTE) {
// reset all labels
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
}
}
void asm_x64_end_pass(asm_x64_t *as) {
if (as->pass == ASM_X64_PASS_COMPUTE) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
if(as->code_base == NULL) {
} if (pass == ASM_X64_PASS_EMIT) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
if (as->code_base == NULL) {
assert(0);
}
//printf("code_size: %u\n", as->code_size);
}
as->pass = pass;
as->code_offset = 0;
}
/*
// check labels are resolved
if (as->label != NULL)
{
int i;
for (i = 0; i < as->label->len; ++i)
if (g_array_index(as->label, Label, i).unresolved != NULL)
return false;
}
*/
void asm_x64_end_pass(asm_x64_t *as) {
// could check labels are resolved...
(void)as;
}
// all functions must go through this one to emit bytes
@@ -282,11 +271,13 @@ void asm_x64_push_i32(asm_x64_t *as, int src_i32) {
}
*/
/*
void asm_x64_push_disp(asm_x64_t *as, int src_r64, int src_offset) {
assert(src_r64 < 8);
asm_x64_write_byte_1(as, OPCODE_PUSH_M64);
asm_x64_write_r64_disp(as, 6, src_r64, src_offset);
}
*/
void asm_x64_pop_r64(asm_x64_t *as, int dest_r64) {
if (dest_r64 < 8) {
@@ -358,7 +349,7 @@ void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
}
void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
STATIC void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
// use REX prefix for 64 bit operation
assert(src_r64 < 8);
assert(dest_r64 < 8);
@@ -366,10 +357,12 @@ void asm_x64_lea_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
}
/*
void asm_x64_mov_i8_to_r8(asm_x64_t *as, int src_i8, int dest_r64) {
assert(dest_r64 < 8);
asm_x64_write_byte_2(as, OPCODE_MOV_I8_TO_R8 | dest_r64, src_i8);
}
*/
STATIC void asm_x64_mov_i32_to_r64(asm_x64_t *as, int src_i32, int dest_r64) {
// cpu defaults to i32 to r64, with zero extension
@@ -509,11 +502,11 @@ void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) {
asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8));
}
void asm_x64_label_assign(asm_x64_t *as, int label) {
void asm_x64_label_assign(asm_x64_t *as, mp_uint_t label) {
assert(label < as->max_num_labels);
if (as->pass < ASM_X64_PASS_EMIT) {
// assign label offset
assert(as->label_offsets[label] == -1);
assert(as->label_offsets[label] == (mp_uint_t)-1);
as->label_offsets[label] = as->code_offset;
} else {
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
@@ -522,15 +515,15 @@ void asm_x64_label_assign(asm_x64_t *as, int label) {
}
}
STATIC mp_uint_t get_label_dest(asm_x64_t *as, int label) {
STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) {
assert(label < as->max_num_labels);
return as->label_offsets[label];
}
void asm_x64_jmp_label(asm_x64_t *as, int label) {
void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {
mp_uint_t dest = get_label_dest(as, label);
mp_int_t rel = dest - as->code_offset;
if (dest != -1 && rel < 0) {
if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump
rel -= 2;
@@ -549,10 +542,10 @@ void asm_x64_jmp_label(asm_x64_t *as, int label) {
}
}
void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, int label) {
void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {
mp_uint_t dest = get_label_dest(as, label);
mp_int_t rel = dest - as->code_offset;
if (dest != -1 && rel < 0) {
if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump
rel -= 2;

View File

@@ -23,6 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_ASMX64_H__
#define __MICROPY_INCLUDED_PY_ASMX64_H__
#include "py/mpconfig.h"
#include "py/misc.h"
// AMD64 calling convention is:
// - args pass in: RDI, RSI, RDX, RCX, R08, R09
@@ -99,12 +104,14 @@ void asm_x64_sub_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b);
void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b);
void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8);
void asm_x64_label_assign(asm_x64_t* as, int label);
void asm_x64_jmp_label(asm_x64_t* as, int label);
void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, int label);
void asm_x64_label_assign(asm_x64_t* as, mp_uint_t label);
void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label);
void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label);
void asm_x64_entry(asm_x64_t* as, int num_locals);
void asm_x64_exit(asm_x64_t* as);
void asm_x64_mov_local_to_r64(asm_x64_t* as, int src_local_num, int dest_r64);
void asm_x64_mov_r64_to_local(asm_x64_t* as, int src_r64, int dest_local_num);
void asm_x64_mov_local_addr_to_r64(asm_x64_t* as, int local_num, int dest_r64);
void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32);
#endif // __MICROPY_INCLUDED_PY_ASMX64_H__

View File

@@ -29,13 +29,12 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "py/mpconfig.h"
// wrapper around everything in this file
#if MICROPY_EMIT_X86
#include "asmx86.h"
#include "py/asmx86.h"
/* all offsets are measured in multiples of 4 bytes */
#define WORD_SIZE (4)
@@ -132,21 +131,21 @@ void asm_x86_free(asm_x86_t *as, bool free_code) {
}
void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_X86_PASS_COMPUTE) {
// reset all labels
memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t));
}
}
void asm_x86_end_pass(asm_x86_t *as) {
if (as->pass == ASM_X86_PASS_COMPUTE) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**) &as->code_base, &as->code_size);
if(as->code_base == NULL) {
} else if (pass == ASM_X86_PASS_EMIT) {
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
if (as->code_base == NULL) {
assert(0);
}
}
as->pass = pass;
as->code_offset = 0;
}
void asm_x86_end_pass(asm_x86_t *as) {
(void)as;
}
// all functions must go through this one to emit bytes
@@ -400,7 +399,7 @@ void asm_x86_label_assign(asm_x86_t *as, mp_uint_t label) {
assert(label < as->max_num_labels);
if (as->pass < ASM_X86_PASS_EMIT) {
// assign label offset
assert(as->label_offsets[label] == -1);
assert(as->label_offsets[label] == (mp_uint_t)-1);
as->label_offsets[label] = as->code_offset;
} else {
// ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT
@@ -409,7 +408,7 @@ void asm_x86_label_assign(asm_x86_t *as, mp_uint_t label) {
}
}
STATIC mp_uint_t get_label_dest(asm_x86_t *as, int label) {
STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) {
assert(label < as->max_num_labels);
return as->label_offsets[label];
}
@@ -417,7 +416,7 @@ STATIC mp_uint_t get_label_dest(asm_x86_t *as, int label) {
void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
mp_uint_t dest = get_label_dest(as, label);
mp_int_t rel = dest - as->code_offset;
if (dest != -1 && rel < 0) {
if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump
rel -= 2;
@@ -439,7 +438,7 @@ void asm_x86_jmp_label(asm_x86_t *as, mp_uint_t label) {
void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {
mp_uint_t dest = get_label_dest(as, label);
mp_int_t rel = dest - as->code_offset;
if (dest != -1 && rel < 0) {
if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump
rel -= 2;

View File

@@ -23,6 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_ASMX86_H__
#define __MICROPY_INCLUDED_PY_ASMX86_H__
#include "py/mpconfig.h"
#include "py/misc.h"
// x86 cdecl calling convention is:
// - args passed on the stack in reverse order
@@ -106,3 +111,5 @@ void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32);
void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num);
void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32);
void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32);
#endif // __MICROPY_INCLUDED_PY_ASMX86_H__

21
py/bc.c
View File

@@ -29,17 +29,9 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "objtuple.h"
#include "objfun.h"
#include "runtime0.h"
#include "runtime.h"
#include "bc.h"
#include "stackctrl.h"
#include "py/nlr.h"
#include "py/objfun.h"
#include "py/bc.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -62,9 +54,8 @@ mp_uint_t mp_decode_uint(const byte **ptr) {
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expected, mp_uint_t given) {
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
// Generic message, to be reused for other argument issues
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"argument num/types mismatch"));
// generic message, used also for other argument issues
mp_arg_error_terse_mismatch();
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"function takes %d positional arguments but %d were given", expected, given));
@@ -125,7 +116,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
// Apply processing and check below only if we don't have kwargs,
// otherwise, kw handling code below has own extensive checks.
if (n_kw == 0 && !self->has_def_kw_args) {
if (n_args >= self->n_pos_args - self->n_def_args) {
if (n_args >= (mp_uint_t)(self->n_pos_args - self->n_def_args)) {
// given enough arguments, but may need to use some default arguments
for (mp_uint_t i = n_args; i < self->n_pos_args; i++) {
code_state->state[n_state - 1 - i] = self->extra_args[i - (self->n_pos_args - self->n_def_args)];

View File

@@ -23,6 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_BC_H__
#define __MICROPY_INCLUDED_PY_BC_H__
#include "py/runtime.h"
#include "py/obj.h"
// Exception stack entry
typedef struct _mp_exc_stack {
@@ -61,3 +66,5 @@ const byte *mp_bytecode_print_str(const byte *ip);
#define MP_TAGPTR_TAG0(x) ((mp_uint_t)(x) & 1)
#define MP_TAGPTR_TAG1(x) ((mp_uint_t)(x) & 2)
#define MP_TAGPTR_MAKE(ptr, tag) ((void*)((mp_uint_t)(ptr) | (tag)))
#endif // __MICROPY_INCLUDED_PY_BC_H__

View File

@@ -23,6 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_BC0_H__
#define __MICROPY_INCLUDED_PY_BC0_H__
// Micro Python byte-codes.
// The comment at the end of the line (if it exists) tells the arguments to the byte-code.
@@ -36,6 +38,7 @@
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
#define MP_BC_LOAD_CONST_OBJ (0x09) // ptr; TODO renumber to be in order
#define MP_BC_LOAD_NULL (0x19)
#define MP_BC_LOAD_FAST_N (0x1a) // uint
@@ -118,3 +121,5 @@
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)
#endif // __MICROPY_INCLUDED_PY_BC0_H__

View File

@@ -30,12 +30,8 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "smallint.h"
#include "binary.h"
#include "py/binary.h"
#include "py/smallint.h"
// Helpers to work with binary-encoded data
@@ -113,24 +109,26 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
mp_int_t val = 0;
switch (typecode) {
case 'b':
val = ((int8_t*)p)[index];
val = ((signed char*)p)[index];
break;
case BYTEARRAY_TYPECODE:
case 'B':
val = ((uint8_t*)p)[index];
val = ((unsigned char*)p)[index];
break;
case 'h':
val = ((int16_t*)p)[index];
val = ((short*)p)[index];
break;
case 'H':
val = ((uint16_t*)p)[index];
val = ((unsigned short*)p)[index];
break;
case 'i':
case 'l':
return mp_obj_new_int(((int32_t*)p)[index]);
return mp_obj_new_int(((int*)p)[index]);
case 'I':
return mp_obj_new_int_from_uint(((unsigned int*)p)[index]);
case 'l':
return mp_obj_new_int(((long*)p)[index]);
case 'L':
return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
return mp_obj_new_int_from_uint(((unsigned long*)p)[index]);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
case 'q':
case 'Q':
@@ -260,7 +258,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
}
}
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, val);
mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
}
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
@@ -281,25 +279,29 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
switch (typecode) {
case 'b':
((int8_t*)p)[index] = val;
((signed char*)p)[index] = val;
break;
case BYTEARRAY_TYPECODE:
case 'B':
val = ((uint8_t*)p)[index] = val;
((unsigned char*)p)[index] = val;
break;
case 'h':
val = ((int16_t*)p)[index] = val;
((short*)p)[index] = val;
break;
case 'H':
val = ((uint16_t*)p)[index] = val;
((unsigned short*)p)[index] = val;
break;
case 'i':
case 'l':
((int32_t*)p)[index] = val;
((int*)p)[index] = val;
break;
case 'I':
((unsigned int*)p)[index] = val;
break;
case 'l':
((long*)p)[index] = val;
break;
case 'L':
((uint32_t*)p)[index] = val;
((unsigned long*)p)[index] = val;
break;
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
case 'q':

View File

@@ -23,6 +23,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_BINARY_H__
#define __MICROPY_INCLUDED_PY_BINARY_H__
#include "py/obj.h"
// Use special typecode to differentiate repr() of bytearray vs array.array('B')
// (underlyingly they're same).
@@ -36,3 +40,5 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src);
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val);
#endif // __MICROPY_INCLUDED_PY_BINARY_H__

View File

@@ -23,9 +23,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_BUILTIN_H__
#define __MICROPY_INCLUDED_PY_BUILTIN_H__
#include "py/obj.h"
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
mp_obj_t mp_micropython_mem_info(mp_uint_t n_args, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
@@ -86,12 +91,6 @@ extern const mp_obj_module_t mp_module_sys;
extern const mp_obj_module_t mp_module_gc;
extern const mp_obj_dict_t mp_module_builtins_globals;
extern mp_obj_dict_t *mp_module_builtins_override_dict;
struct _dummy_t;
extern struct _dummy_t mp_sys_stdin_obj;
extern struct _dummy_t mp_sys_stdout_obj;
extern struct _dummy_t mp_sys_stderr_obj;
// extmod modules
extern const mp_obj_module_t mp_module_uctypes;
@@ -101,3 +100,5 @@ extern const mp_obj_module_t mp_module_ure;
extern const mp_obj_module_t mp_module_uheapq;
extern const mp_obj_module_t mp_module_uhashlib;
extern const mp_obj_module_t mp_module_ubinascii;
#endif // __MICROPY_INCLUDED_PY_BUILTIN_H__

View File

@@ -26,20 +26,11 @@
#include <stdint.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
#include "objfun.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "py/nlr.h"
#include "py/objfun.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/builtin.h"
#if MICROPY_PY_BUILTINS_COMPILE
@@ -84,6 +75,8 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t loc
}
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args;
// get the source
mp_uint_t str_len;
const char *str = mp_obj_str_get_data(args[0], &str_len);

View File

@@ -25,25 +25,16 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "lexerunix.h"
#include "parse.h"
#include "obj.h"
#include "objmodule.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "py/nlr.h"
#include "py/compile.h"
#include "py/objmodule.h"
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/frozenmod.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -119,9 +110,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
#endif
}
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) {
if (lex == NULL) {
// we verified the file exists using stat, but lexer could still fail
@@ -129,7 +118,7 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found"));
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
"no module named '%s'", vstr_str(file)));
"no module named '%s'", fname));
}
}
@@ -143,6 +132,12 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
}
STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
// create the lexer
mp_lexer_t *lex = mp_lexer_new_from_file(vstr_str(file));
do_load_from_lexer(module_obj, lex, vstr_str(file));
}
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
#if DEBUG_PRINT
DEBUG_printf("__import__:\n");
@@ -213,7 +208,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import"));
}
uint new_mod_l = (mod_len == 0 ? p - this_name : 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);
char *new_mod = alloca(new_mod_l);
memcpy(new_mod, this_name, p - this_name);
if (mod_len != 0) {
@@ -229,7 +224,8 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
}
// check if module already exists
mp_obj_t module_obj = mp_module_get(mp_obj_str_get_qstr(module_name));
qstr module_name_qstr = mp_obj_str_get_qstr(module_name);
mp_obj_t module_obj = mp_module_get(module_name_qstr);
if (module_obj != MP_OBJ_NULL) {
DEBUG_printf("Module already loaded\n");
// If it's not a package, return module right away
@@ -247,6 +243,15 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
}
DEBUG_printf("Module not yet loaded\n");
#if MICROPY_MODULE_FROZEN
mp_lexer_t *lex = mp_find_frozen_module(mod_str, mod_len);
if (lex != NULL) {
module_obj = mp_obj_new_module(module_name_qstr);
do_load_from_lexer(module_obj, lex, mod_str);
return module_obj;
}
#endif
uint last = 0;
VSTR_FIXED(path, MICROPY_ALLOC_PATH_MAX)
module_obj = MP_OBJ_NULL;
@@ -323,7 +328,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
vstr_add_str(&path, "__init__.py");
if (mp_import_stat(vstr_str(&path)) != MP_IMPORT_STAT_FILE) {
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py
printf("Notice: %s is imported as namespace package\n", vstr_str(&path));
mp_warning("%s is imported as namespace package", vstr_str(&path));
} else {
do_load(module_obj, &path);
vstr_cut_tail_bytes(&path, sizeof("/__init__.py") - 1); // cut off /__init__.py

View File

@@ -31,29 +31,22 @@
#include <assert.h>
#include <math.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "runtime0.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "emit.h"
#include "compile.h"
#include "runtime.h"
#include "builtin.h"
#include "smallint.h"
#include "py/scope.h"
#include "py/emit.h"
#include "py/compile.h"
#include "py/smallint.h"
#include "py/runtime.h"
#include "py/builtin.h"
// TODO need to mangle __attr names
typedef enum {
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
#include "grammar.h"
#include "py/grammar.h"
#undef DEF_RULE
PN_maximum_number_of,
PN_string, // special node for non-interned string
PN_bytes, // special node for non-interned bytes
} pn_kind_t;
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
@@ -106,6 +99,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
comp->compile_error = exc;
}
#if MICROPY_COMP_MODULE_CONST
STATIC const mp_map_elem_t mp_constants_table[] = {
#if MICROPY_PY_UCTYPES
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
@@ -113,14 +107,8 @@ STATIC const mp_map_elem_t mp_constants_table[] = {
// Extra constants as defined by a port
MICROPY_PORT_CONSTANTS
};
STATIC const mp_map_t mp_constants_map = {
.all_keys_are_qstrs = 1,
.table_is_fixed_array = 1,
.used = MP_ARRAY_SIZE(mp_constants_table),
.alloc = MP_ARRAY_SIZE(mp_constants_table),
.table = (mp_map_elem_t*)mp_constants_table,
};
STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);
#endif
// this function is essentially a simple preprocessor
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
@@ -185,6 +173,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
break;
#endif
case PN_string:
case PN_bytes:
return pn;
}
@@ -227,12 +216,12 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
// int << int
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
if (!(arg1 >= (mp_int_t)BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
}
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
// int >> int
if (arg1 >= BITS_PER_WORD) {
if (arg1 >= (mp_int_t)BITS_PER_WORD) {
// Shifting to big amounts is underfined behavior
// in C and is CPU-dependent; propagate sign bit.
arg1 = BITS_PER_WORD - 1;
@@ -335,6 +324,7 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
}
}
#endif
#if MICROPY_COMP_MODULE_CONST
} else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
// id.id
// look it up in constant table, see if it can be replaced with an integer
@@ -348,11 +338,10 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
mp_load_method_maybe(elem->value, q_attr, dest);
if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
if (MP_SMALL_INT_FITS(val)) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
}
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
}
}
#endif
}
break;
}
@@ -397,8 +386,8 @@ STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse
return scope;
}
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, int pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
if (MP_PARSE_NODE_IS_STRUCT(pn) && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn) == pn_list_kind) {
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < num_nodes; i++) {
@@ -409,7 +398,7 @@ STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, int pn
}
}
STATIC int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
STATIC int list_get(mp_parse_node_t *pn, pn_kind_t pn_kind, mp_parse_node_t **nodes) {
if (MP_PARSE_NODE_IS_NULL(*pn)) {
*nodes = NULL;
return 0;
@@ -440,6 +429,9 @@ STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
return true;
}
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
return true;
}
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
return false;
}
@@ -488,9 +480,9 @@ STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len,
}
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string) || MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes));
return;
}
@@ -819,14 +811,14 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;
// look for star expression
int have_star_index = -1;
uint have_star_index = -1;
if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
EMIT_ARG(unpack_ex, 0, num_tail);
have_star_index = 0;
}
for (int i = 0; i < num_tail; i++) {
for (uint i = 0; i < num_tail; i++) {
if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
if (have_star_index < 0) {
if (have_star_index == (uint)-1) {
EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
have_star_index = num_head + i;
} else {
@@ -835,7 +827,7 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
}
}
}
if (have_star_index < 0) {
if (have_star_index == (uint)-1) {
EMIT_ARG(unpack_sequence, num_head + num_tail);
}
if (num_head != 0) {
@@ -845,7 +837,7 @@ STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num
c_assign(comp, node_head, ASSIGN_STORE);
}
}
for (int i = 0; i < num_tail; i++) {
for (uint i = 0; i < num_tail; i++) {
if (num_head + i == have_star_index) {
c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE);
} else {
@@ -868,6 +860,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
EMIT_ARG(store_id, arg);
break;
case ASSIGN_AUG_LOAD:
default:
EMIT_ARG(load_id, arg);
break;
}
@@ -988,7 +981,7 @@ STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int
EMIT_ARG(load_closure, id->qst, id->local_num);
#else
// in Micro Python we load closures using LOAD_FAST
EMIT_ARG(load_fast, id->qst, id->flags, id->local_num);
EMIT_ARG(load_fast, id->qst, id->local_num);
#endif
nfree += 1;
}
@@ -1236,9 +1229,9 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
// compile the decorator function
compile_node(comp, name_nodes[0]);
for (int i = 1; i < name_len; i++) {
assert(MP_PARSE_NODE_IS_ID(name_nodes[i])); // should be
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[i]));
for (int j = 1; j < name_len; j++) {
assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be
EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]));
}
// nodes[1] contains arguments to the decorator function, if any
@@ -1995,6 +1988,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
// this is a catch all exception handler
if (i + 1 != n_except) {
compile_syntax_error(comp, pn_excepts[i], "default 'except:' must be last");
compile_decrease_except_level(comp);
return;
}
} else {
@@ -2164,7 +2158,8 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
} else {
// for non-REPL, evaluate then discard the expression
if ((MP_PARSE_NODE_IS_LEAF(pns->nodes[0]) && !MP_PARSE_NODE_IS_ID(pns->nodes[0]))
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)) {
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_string)
|| MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_bytes)) {
// do nothing with a lonely constant
} else {
compile_node(comp, pns->nodes[0]); // just an expression
@@ -2191,8 +2186,7 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
case MP_TOKEN_DEL_DBL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_FLOOR_DIVIDE; break;
case MP_TOKEN_DEL_SLASH_EQUAL: op = MP_BINARY_OP_INPLACE_TRUE_DIVIDE; break;
case MP_TOKEN_DEL_PERCENT_EQUAL: op = MP_BINARY_OP_INPLACE_MODULO; break;
case MP_TOKEN_DEL_DBL_STAR_EQUAL: op = MP_BINARY_OP_INPLACE_POWER; break;
default: assert(0); op = MP_BINARY_OP_INPLACE_OR; // shouldn't happen
case MP_TOKEN_DEL_DBL_STAR_EQUAL: default: op = MP_BINARY_OP_INPLACE_POWER; break;
}
EMIT_ARG(binary_op, op);
c_assign(comp, pns->nodes[0], ASSIGN_AUG_STORE); // lhs store for aug assign
@@ -2356,8 +2350,7 @@ STATIC void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
case MP_TOKEN_OP_LESS_EQUAL: op = MP_BINARY_OP_LESS_EQUAL; break;
case MP_TOKEN_OP_MORE_EQUAL: op = MP_BINARY_OP_MORE_EQUAL; break;
case MP_TOKEN_OP_NOT_EQUAL: op = MP_BINARY_OP_NOT_EQUAL; break;
case MP_TOKEN_KW_IN: op = MP_BINARY_OP_IN; break;
default: assert(0); op = MP_BINARY_OP_LESS; // shouldn't happen
case MP_TOKEN_KW_IN: default: op = MP_BINARY_OP_IN; break;
}
EMIT_ARG(binary_op, op);
} else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])) {
@@ -2494,7 +2487,7 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
for (int i = 0; i < comp->scope_cur->id_info_len; i++) {
if (comp->scope_cur->id_info[i].flags & ID_FLAG_IS_PARAM) {
// first argument found; load it and call super
EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].flags, comp->scope_cur->id_info[i].local_num);
EMIT_ARG(load_fast, MP_QSTR_, comp->scope_cur->id_info[i].local_num);
EMIT_ARG(call_function, 2, 0, 0);
return;
}
@@ -2608,8 +2601,12 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
} else {
assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[i]));
mp_parse_node_struct_t *pns_string = (mp_parse_node_struct_t*)pns->nodes[i];
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string);
pn_kind = MP_PARSE_NODE_STRING;
if (MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_string) {
pn_kind = MP_PARSE_NODE_STRING;
} else {
assert(MP_PARSE_NODE_STRUCT_KIND(pns_string) == PN_bytes);
pn_kind = MP_PARSE_NODE_BYTES;
}
n_bytes += (mp_uint_t)pns_string->nodes[1];
}
if (i == 0) {
@@ -2620,9 +2617,16 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
// if we are not in the last pass, just load a dummy object
if (comp->pass != MP_PASS_EMIT) {
EMIT_ARG(load_const_obj, mp_const_none);
return;
}
// concatenate string/bytes
byte *q_ptr;
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
vstr_t vstr;
vstr_init_len(&vstr, n_bytes);
byte *s_dest = (byte*)vstr.buf;
for (int i = 0; i < n; i++) {
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
mp_uint_t s_len;
@@ -2635,9 +2639,9 @@ STATIC void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
s_dest += (mp_uint_t)pns_string->nodes[1];
}
}
qstr q = qstr_build_end(q_ptr);
EMIT_ARG(load_const_str, q, string_kind == MP_PARSE_NODE_BYTES);
// load the object
EMIT_ARG(load_const_obj, mp_obj_new_str_from_vstr(string_kind == MP_PARSE_NODE_STRING ? &mp_type_str : &mp_type_bytes, &vstr));
}
// pns needs to have 2 nodes, first is lhs of comprehension, second is PN_comp_for node
@@ -2775,9 +2779,9 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
// process rest of elements
for (int i = 0; i < n; i++) {
mp_parse_node_t pn = nodes[i];
bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dictorsetmaker_item);
compile_node(comp, pn);
mp_parse_node_t pn_i = nodes[i];
bool is_key_value = MP_PARSE_NODE_IS_STRUCT_KIND(pn_i, PN_dictorsetmaker_item);
compile_node(comp, pn_i);
if (is_dict) {
if (!is_key_value) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dictionary");
@@ -2932,15 +2936,36 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
STATIC void compile_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
// only create and load the actual str object on the last pass
if (comp->pass != MP_PASS_EMIT) {
EMIT_ARG(load_const_obj, mp_const_none);
} else {
EMIT_ARG(load_const_obj, mp_obj_new_str((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false));
}
}
STATIC void compile_bytes(compiler_t *comp, mp_parse_node_struct_t *pns) {
// only create and load the actual bytes object on the last pass
if (comp->pass != MP_PASS_EMIT) {
EMIT_ARG(load_const_obj, mp_const_none);
} else {
EMIT_ARG(load_const_obj, mp_obj_new_bytes((const byte*)pns->nodes[0], (mp_uint_t)pns->nodes[1]));
}
}
typedef void (*compile_function_t)(compiler_t*, mp_parse_node_struct_t*);
STATIC compile_function_t compile_function[] = {
#define nc NULL
#define c(f) compile_##f
#define DEF_RULE(rule, comp, kind, ...) comp,
#include "grammar.h"
#include "py/grammar.h"
#undef nc
#undef c
#undef DEF_RULE
NULL,
compile_string,
compile_bytes,
};
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
@@ -2957,7 +2982,7 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
case MP_PARSE_NODE_DECIMAL: EMIT_ARG(load_const_dec, arg); break;
case MP_PARSE_NODE_STRING: EMIT_ARG(load_const_str, arg, false); break;
case MP_PARSE_NODE_BYTES: EMIT_ARG(load_const_str, arg, true); break;
case MP_PARSE_NODE_TOKEN:
case MP_PARSE_NODE_TOKEN: default:
if (arg == MP_TOKEN_NEWLINE) {
// this can occur when file_input lets through a NEWLINE (eg if file starts with a newline)
// or when single_input lets through a NEWLINE (user enters a blank line)
@@ -2966,24 +2991,19 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) {
EMIT_ARG(load_const_tok, arg);
}
break;
default: assert(0);
}
} else {
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
EMIT_ARG(set_line_number, pns->source_line);
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_string) {
EMIT_ARG(load_const_str, qstr_from_strn((const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1]), false);
} else {
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)];
if (f == NULL) {
#if MICROPY_DEBUG_PRINTERS
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
mp_parse_node_print(pn, 0);
printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
mp_parse_node_print(pn, 0);
#endif
compile_syntax_error(comp, pn, "internal compiler error");
} else {
f(comp, pns);
}
compile_syntax_error(comp, pn, "internal compiler error");
} else {
f(comp, pns);
}
}
}
@@ -3191,6 +3211,9 @@ STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
EMIT_ARG(store_id, MP_QSTR___doc__);
}
}
#else
(void)comp;
(void)pn;
#endif
}
@@ -3365,7 +3388,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
#if MICROPY_EMIT_CPYTHON
EMIT_ARG(load_closure, MP_QSTR___class__, 0); // XXX check this is the correct local num
#else
EMIT_ARG(load_fast, MP_QSTR___class__, id->flags, id->local_num);
EMIT_ARG(load_fast, MP_QSTR___class__, id->local_num);
#endif
}
EMIT(return_value);
@@ -3470,12 +3493,12 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
}
if (pass > MP_PASS_SCOPE) {
mp_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
for (uint i = 1; i < n_args; i++) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
for (uint j = 1; j < n_args; j++) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[j])) {
compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires integer arguments");
return;
}
EMIT_INLINE_ASM_ARG(data, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[i]));
EMIT_INLINE_ASM_ARG(data, bytesize, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[j]));
}
}
} else {
@@ -3495,7 +3518,7 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
}
#endif
STATIC void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
STATIC void scope_compute_things(scope_t *scope) {
#if !MICROPY_EMIT_CPYTHON
// in Micro Python we put the *x parameter after all other parameters (except **y)
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
@@ -3659,7 +3682,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
// compute some things related to scope and identifiers
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
compile_scope_compute_things(comp, s);
scope_compute_things(s);
}
// finish with pass 1
@@ -3731,10 +3754,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
#endif
comp->emit = emit_native;
EMIT_ARG(set_native_type, MP_EMIT_NATIVE_TYPE_ENABLE, s->emit_options == MP_EMIT_OPT_VIPER, 0);
// native emitters need an extra pass to compute stack size
compile_scope(comp, s, MP_PASS_STACK_SIZE);
break;
#endif // MICROPY_EMIT_NATIVE
@@ -3748,6 +3767,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
}
#endif // !MICROPY_EMIT_CPYTHON
// need a pass to compute stack size
compile_scope(comp, s, MP_PASS_STACK_SIZE);
// second last pass: compute code size
if (comp->compile_error == MP_OBJ_NULL) {
compile_scope(comp, s, MP_PASS_CODE_SIZE);

View File

@@ -24,6 +24,13 @@
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_EMIT_H__
#define __MICROPY_INCLUDED_PY_EMIT_H__
#include "py/lexer.h"
#include "py/scope.h"
#include "py/runtime0.h"
/* Notes on passes:
* We don't know exactly the opcodes in pass 1 because they depend on the
* closing over of variables (LOAD_CLOSURE, BUILD_TUPLE, MAKE_CLOSURE), which
@@ -33,10 +40,6 @@
* This is problematic for some emitters (x64) since they need to know the maximum
* stack size to compile the entry to the function, and this affects code size.
*/
#ifndef __MICROPY_INCLUDED_PY_EMIT_H__
#define __MICROPY_INCLUDED_PY_EMIT_H__
#include "py/runtime0.h"
typedef enum {
MP_PASS_SCOPE = 1, // work out id's and their kind, and number of labels
@@ -77,8 +80,9 @@ typedef struct _emit_method_table_t {
void (*load_const_int)(emit_t *emit, qstr qst);
void (*load_const_dec)(emit_t *emit, qstr qst);
void (*load_const_str)(emit_t *emit, qstr qst, bool bytes);
void (*load_const_obj)(emit_t *emit, void *obj);
void (*load_null)(emit_t *emit);
void (*load_fast)(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num);
void (*load_fast)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*load_deref)(emit_t *emit, qstr qst, mp_uint_t local_num);
void (*load_name)(emit_t *emit, qstr qst);
void (*load_global)(emit_t *emit, qstr qst);
@@ -204,4 +208,10 @@ extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table;
emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels);
void emit_inline_thumb_free(emit_inline_asm_t *emit);
#if MICROPY_WARNINGS
void mp_emitter_warning(pass_kind_t pass, const char *msg);
#else
#define mp_emitter_warning(pass, msg)
#endif
#endif // __MICROPY_INCLUDED_PY_EMIT_H__

View File

@@ -30,17 +30,9 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
#include "bc0.h"
#include "py/mpstate.h"
#include "py/emit.h"
#include "py/bc0.h"
#if !MICROPY_EMIT_CPYTHON
@@ -276,6 +268,10 @@ STATIC void emit_write_bytecode_byte_signed_label(emit_t* emit, byte b1, mp_uint
}
STATIC void emit_bc_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
(void)emit;
(void)op;
(void)arg1;
(void)arg2;
}
STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -392,7 +388,7 @@ STATIC void emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta) {
STATIC void emit_bc_set_source_line(emit_t *emit, mp_uint_t source_line) {
//printf("source: line %d -> %d offset %d -> %d\n", emit->last_source_line, source_line, emit->last_source_line_offset, emit->bytecode_offset);
#if MICROPY_ENABLE_SOURCE_LINE
if (mp_optimise_value >= 3) {
if (MP_STATE_VM(mp_optimise_value) >= 3) {
// If we compile with -O3, don't store line numbers.
return;
}
@@ -432,7 +428,7 @@ STATIC void emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
assert(l < emit->max_num_labels);
if (emit->pass < MP_PASS_EMIT) {
// assign label offset
assert(emit->label_offsets[l] == -1);
assert(emit->label_offsets[l] == (mp_uint_t)-1);
emit->label_offsets[l] = emit->bytecode_offset;
} else {
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
@@ -462,8 +458,9 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
case MP_TOKEN_KW_FALSE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_FALSE); break;
case MP_TOKEN_KW_NONE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_NONE); break;
case MP_TOKEN_KW_TRUE: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_TRUE); break;
no_other_choice:
case MP_TOKEN_ELLIPSIS: emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_ELLIPSIS); break;
default: assert(0);
default: assert(0); goto no_other_choice; // to help flow control analysis
}
}
@@ -495,12 +492,18 @@ STATIC void emit_bc_load_const_str(emit_t *emit, qstr qst, bool bytes) {
}
}
STATIC void emit_bc_load_const_obj(emit_t *emit, void *obj) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_ptr(emit, MP_BC_LOAD_CONST_OBJ, obj);
}
STATIC void emit_bc_load_null(emit_t *emit) {
emit_bc_pre(emit, 1);
emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
};
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
assert(local_num >= 0);
emit_bc_pre(emit, 1);
if (local_num <= 15) {
@@ -511,23 +514,35 @@ STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uin
}
STATIC void emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
}
STATIC void emit_bc_load_name(emit_t *emit, qstr qst) {
(void)qst;
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
emit_write_bytecode_byte(emit, 0);
}
}
STATIC void emit_bc_load_global(emit_t *emit, qstr qst) {
(void)qst;
emit_bc_pre(emit, 1);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
emit_write_bytecode_byte(emit, 0);
}
}
STATIC void emit_bc_load_attr(emit_t *emit, qstr qst) {
emit_bc_pre(emit, 0);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
emit_write_bytecode_byte(emit, 0);
}
}
STATIC void emit_bc_load_method(emit_t *emit, qstr qst) {
@@ -546,6 +561,7 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
}
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
assert(local_num >= 0);
emit_bc_pre(emit, -1);
if (local_num <= 15) {
@@ -556,6 +572,7 @@ STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
}
STATIC void emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
emit_bc_pre(emit, -1);
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
}
@@ -573,6 +590,9 @@ STATIC void emit_bc_store_global(emit_t *emit, qstr qst) {
STATIC void emit_bc_store_attr(emit_t *emit, qstr qst) {
emit_bc_pre(emit, -2);
emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) {
emit_write_bytecode_byte(emit, 0);
}
}
STATIC void emit_bc_store_subscr(emit_t *emit) {
@@ -581,10 +601,12 @@ STATIC void emit_bc_store_subscr(emit_t *emit) {
}
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
}
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
(void)qst;
emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
}
@@ -913,6 +935,7 @@ const emit_method_table_t emit_bc_method_table = {
emit_bc_load_const_int,
emit_bc_load_const_dec,
emit_bc_load_const_str,
emit_bc_load_const_obj,
emit_bc_load_null,
emit_bc_load_fast,
emit_bc_load_deref,

View File

@@ -28,16 +28,7 @@
#include <stdint.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "runtime0.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "emit.h"
#include "py/emit.h"
#define EMIT(fun, ...) (emit_method_table->fun(emit, __VA_ARGS__))
@@ -53,7 +44,7 @@ void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_ta
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
EMIT(load_global, qst);
} else if (id->kind == ID_INFO_KIND_LOCAL) {
EMIT(load_fast, qst, id->flags, id->local_num);
EMIT(load_fast, qst, id->local_num);
} else if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
EMIT(load_deref, qst, id->local_num);
} else {

View File

@@ -30,16 +30,7 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
#include "py/emit.h"
// wrapper around everything in this file
#if MICROPY_EMIT_CPYTHON
@@ -240,12 +231,21 @@ STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qst, bool bytes) {
}
}
STATIC void emit_cpy_load_const_obj(emit_t *emit, void *obj) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_CONST ");
mp_obj_print(obj, PRINT_REPR);
printf("\n");
}
}
STATIC void emit_cpy_load_null(emit_t *emit) {
// unused for cpy
assert(0);
}
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_pre(emit, 1, 3);
if (emit->pass == MP_PASS_EMIT) {
printf("LOAD_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
@@ -842,6 +842,7 @@ const emit_method_table_t emit_cpython_method_table = {
emit_cpy_load_const_int,
emit_cpy_load_const_dec,
emit_cpy_load_const_str,
emit_cpy_load_const_obj,
emit_cpy_load_null,
emit_cpy_load_fast,
emit_cpy_load_deref,

View File

@@ -30,14 +30,9 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
#include "emitglue.h"
#include "bc.h"
#include "py/emitglue.h"
#include "py/runtime0.h"
#include "py/bc.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -49,6 +44,23 @@
#define DEBUG_OP_printf(...) (void)0
#endif
struct _mp_raw_code_t {
mp_raw_code_kind_t kind : 3;
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
mp_uint_t n_kwonly_args : 11;
union {
struct {
byte *code;
mp_uint_t len;
} u_byte;
struct {
void *fun_data;
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
} u_native;
} data;
};
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
rc->kind = MP_CODE_RESERVED;
@@ -60,8 +72,8 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len,
rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args;
rc->n_kwonly_args = n_kwonly_args;
rc->u_byte.code = code;
rc->u_byte.len = len;
rc->data.u_byte.code = code;
rc->data.u_byte.len = len;
#ifdef DEBUG_PRINT
DEBUG_printf("assign byte code: code=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", code, len, n_pos_args, n_kwonly_args, (uint)scope_flags);
@@ -79,8 +91,8 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
rc->kind = kind;
rc->scope_flags = 0;
rc->n_pos_args = n_args;
rc->u_native.fun_data = fun_data;
rc->u_native.type_sig = type_sig;
rc->data.u_native.fun_data = fun_data;
rc->data.u_native.type_sig = type_sig;
#ifdef DEBUG_PRINT
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
@@ -97,6 +109,8 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
fwrite(fun_data, fun_len, 1, fp_write_code);
fclose(fp_write_code);
#endif
#else
(void)fun_len;
#endif
}
#endif
@@ -115,25 +129,26 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
mp_obj_t fun;
switch (rc->kind) {
case MP_CODE_BYTECODE:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->u_byte.code);
no_other_choice:
fun = mp_obj_new_fun_bc(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->data.u_byte.code);
break;
#if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->u_native.fun_data);
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->data.u_native.fun_data);
break;
case MP_CODE_NATIVE_VIPER:
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->u_native.fun_data, rc->u_native.type_sig);
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);
break;
#endif
#if MICROPY_EMIT_INLINE_THUMB
case MP_CODE_NATIVE_ASM:
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->u_native.fun_data);
fun = mp_obj_new_fun_asm(rc->n_pos_args, rc->data.u_native.fun_data);
break;
#endif
default:
// raw code was never set (this should not happen)
assert(0);
return mp_const_none;
goto no_other_choice; // to help flow control analysis
}
// check for generator functions and if so wrap in generator object

View File

@@ -26,6 +26,8 @@
#ifndef __MICROPY_INCLUDED_PY_EMITGLUE_H__
#define __MICROPY_INCLUDED_PY_EMITGLUE_H__
#include "py/obj.h"
// These variables and functions glue the code emitters to the runtime.
typedef enum {
@@ -37,22 +39,7 @@ typedef enum {
MP_CODE_NATIVE_ASM,
} mp_raw_code_kind_t;
typedef struct _mp_raw_code_t {
mp_raw_code_kind_t kind : 3;
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
mp_uint_t n_kwonly_args : 11;
union {
struct {
byte *code;
mp_uint_t len;
} u_byte;
struct {
void *fun_data;
mp_uint_t type_sig; // for viper, compressed as 2-bit types; ret is MSB, then arg0, arg1, etc
} u_native;
};
} mp_raw_code_t;
typedef struct _mp_raw_code_t mp_raw_code_t;
mp_raw_code_t *mp_emit_glue_new_raw_code(void);

View File

@@ -30,23 +30,14 @@
#include <stdarg.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
#include "asmthumb.h"
#include "py/emit.h"
#include "py/asmthumb.h"
#if MICROPY_EMIT_INLINE_THUMB
typedef enum {
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
#include "grammar.h"
#include "py/grammar.h"
#undef DEF_RULE
PN_maximum_number_of,
} pn_kind_t;

View File

@@ -42,24 +42,12 @@
// for x in l[0:8]: can be compiled into a native loop if l has pointer type
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
#include "runtime.h"
#include "py/nlr.h"
#include "py/emit.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@@ -78,7 +66,7 @@
// x64 specific stuff
#include "asmx64.h"
#include "py/asmx64.h"
#define EXPORT_FUN(name) emit_native_x64_##name
@@ -163,7 +151,7 @@
// x86 specific stuff
#include "asmx86.h"
#include "py/asmx86.h"
STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
[MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
@@ -295,7 +283,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
// thumb specific stuff
#include "asmthumb.h"
#include "py/asmthumb.h"
#define EXPORT_FUN(name) emit_native_thumb_##name
@@ -378,7 +366,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
// ARM specific stuff
#include "asmarm.h"
#include "py/asmarm.h"
#define EXPORT_FUN(name) emit_native_arm_##name
@@ -492,7 +480,7 @@ typedef struct _stack_info_t {
union {
int u_reg;
mp_int_t u_imm;
};
} data;
} stack_info_t;
struct _emit_t {
@@ -724,7 +712,7 @@ STATIC void adjust_stack(emit_t *emit, mp_int_t stack_size_delta) {
DEBUG_printf(" adjust_stack; stack_size=%d+%d; stack now:", emit->stack_size - stack_size_delta, stack_size_delta);
for (int i = 0; i < emit->stack_size; i++) {
stack_info_t *si = &emit->stack_info[i];
DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->u_reg);
DEBUG_printf(" (v=%d k=%d %d)", si->vtype, si->kind, si->data.u_reg);
}
DEBUG_printf("\n");
#endif
@@ -752,6 +740,8 @@ STATIC void emit_native_adjust_stack_size(emit_t *emit, mp_int_t delta) {
}
STATIC void emit_native_set_source_line(emit_t *emit, mp_uint_t source_line) {
(void)emit;
(void)source_line;
}
/*
@@ -775,7 +765,7 @@ STATIC void emit_native_pre(emit_t *emit) {
case STACK_REG:
// TODO only push reg if in regs_needed
emit->stack_info[i].kind = STACK_VALUE;
ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].u_reg, emit->stack_start + i);
ASM_MOV_REG_TO_LOCAL(emit->as, emit->stack_info[i].data.u_reg, emit->stack_start + i);
break;
case STACK_IMM:
@@ -805,9 +795,9 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
for (int i = 0; i < emit->stack_size; i++) {
if (i != skip_stack_pos) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG && si->u_reg == reg_needed) {
if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {
si->kind = STACK_VALUE;
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
}
}
}
@@ -818,7 +808,7 @@ STATIC void need_reg_all(emit_t *emit) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG) {
si->kind = STACK_VALUE;
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
}
}
}
@@ -828,17 +818,17 @@ STATIC void need_stack_settled(emit_t *emit) {
for (int i = 0; i < emit->stack_size; i++) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG) {
DEBUG_printf(" reg(%u) to local(%u)\n", si->u_reg, emit->stack_start + i);
DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
si->kind = STACK_VALUE;
ASM_MOV_REG_TO_LOCAL(emit->as, si->u_reg, emit->stack_start + i);
ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
}
}
for (int i = 0; i < emit->stack_size; i++) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_IMM) {
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->u_imm, emit->stack_start + i);
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
si->kind = STACK_VALUE;
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + i, REG_TEMP0);
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0);
}
}
}
@@ -854,13 +844,13 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re
break;
case STACK_REG:
if (si->u_reg != reg_dest) {
ASM_MOV_REG_REG(emit->as, reg_dest, si->u_reg);
if (si->data.u_reg != reg_dest) {
ASM_MOV_REG_REG(emit->as, reg_dest, si->data.u_reg);
}
break;
case STACK_IMM:
ASM_MOV_IMM_TO_REG(emit->as, si->u_imm, reg_dest);
ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest);
break;
}
}
@@ -874,7 +864,7 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
// if folded element was on the stack we need to put it in a register
ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest);
si->kind = STACK_REG;
si->u_reg = reg_dest;
si->data.u_reg = reg_dest;
}
adjust_stack(emit, -1);
}
@@ -884,9 +874,9 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
STATIC void emit_pre_pop_reg_flexible(emit_t *emit, vtype_kind_t *vtype, int *reg_dest, int not_r1, int not_r2) {
emit->last_emit_was_return_value = false;
stack_info_t *si = peek_stack(emit, 0);
if (si->kind == STACK_REG && si->u_reg != not_r1 && si->u_reg != not_r2) {
if (si->kind == STACK_REG && si->data.u_reg != not_r1 && si->data.u_reg != not_r2) {
*vtype = si->vtype;
*reg_dest = si->u_reg;
*reg_dest = si->data.u_reg;
need_reg_single(emit, *reg_dest, 1);
} else {
emit_access_stack(emit, 1, vtype, *reg_dest);
@@ -917,6 +907,7 @@ STATIC void emit_pre_pop_reg_reg_reg(emit_t *emit, vtype_kind_t *vtypea, int reg
}
STATIC void emit_post(emit_t *emit) {
(void)emit;
}
STATIC void emit_post_top_set_vtype(emit_t *emit, vtype_kind_t new_vtype) {
@@ -928,7 +919,7 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg) {
stack_info_t *si = &emit->stack_info[emit->stack_size];
si->vtype = vtype;
si->kind = STACK_REG;
si->u_reg = reg;
si->data.u_reg = reg;
adjust_stack(emit, 1);
}
@@ -936,7 +927,7 @@ STATIC void emit_post_push_imm(emit_t *emit, vtype_kind_t vtype, mp_int_t imm) {
stack_info_t *si = &emit->stack_info[emit->stack_size];
si->vtype = vtype;
si->kind = STACK_IMM;
si->u_imm = imm;
si->data.u_imm = imm;
adjust_stack(emit, 1);
}
@@ -1008,10 +999,10 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
si->kind = STACK_VALUE;
switch (si->vtype) {
case VTYPE_PYOBJ:
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
break;
case VTYPE_BOOL:
if (si->u_imm == 0) {
if (si->data.u_imm == 0) {
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
} else {
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
@@ -1020,7 +1011,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
break;
case VTYPE_INT:
case VTYPE_UINT:
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (si->data.u_imm << 1) | 1, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
si->vtype = VTYPE_PYOBJ;
break;
default:
@@ -1184,13 +1175,20 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst, bool bytes) {
}
}
STATIC void emit_native_load_const_obj(emit_t *emit, void *obj) {
emit_native_pre(emit);
need_reg_single(emit, REG_RET, 0);
ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
STATIC void emit_native_load_null(emit_t *emit) {
emit_native_pre(emit);
emit_post_push_imm(emit, VTYPE_PYOBJ, 0);
}
STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
DEBUG_printf("load_fast(%s, " UINT_FMT ", " UINT_FMT ")\n", qstr_str(qst), id_flags, local_num);
STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
DEBUG_printf("load_fast(%s, " UINT_FMT ")\n", qstr_str(qst), local_num);
vtype_kind_t vtype = emit->local_vtype[local_num];
if (vtype == VTYPE_UNBOUND) {
printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
@@ -1252,6 +1250,9 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp
STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
// not implemented
// in principle could support this quite easily (ldr r0, [r0, #0]) and then get closed over variables!
(void)emit;
(void)qst;
(void)local_num;
assert(0);
}
@@ -1331,7 +1332,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
stack_info_t *top = peek_stack(emit, 0);
if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
// index is an immediate
mp_int_t index_value = top->u_imm;
mp_int_t index_value = top->data.u_imm;
emit_pre_pop_discard(emit); // discard index
int reg_base = REG_ARG_1;
int reg_index = REG_ARG_2;
@@ -1470,6 +1471,9 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num)
STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
// not implemented
(void)emit;
(void)qst;
(void)local_num;
assert(0);
}
@@ -1527,7 +1531,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
stack_info_t *top = peek_stack(emit, 0);
if (top->vtype == VTYPE_INT && top->kind == STACK_IMM) {
// index is an immediate
mp_int_t index_value = top->u_imm;
mp_int_t index_value = top->data.u_imm;
emit_pre_pop_discard(emit); // discard index
vtype_kind_t vtype_value;
int reg_base = REG_ARG_1;
@@ -1636,10 +1640,19 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
// TODO implement me!
// could support for Python types, just set to None (so GC can reclaim it)
// local is automatically deleted for exception block "as" var, and the message
// breaks tests.
//mp_emitter_warning(emit->pass, "Native codegeneration doesn't support deleting local");
(void)emit;
(void)qst;
(void)local_num;
}
STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
// TODO implement me!
(void)emit;
(void)qst;
(void)local_num;
}
STATIC void emit_native_delete_name(emit_t *emit, qstr qst) {
@@ -1713,7 +1726,7 @@ STATIC void emit_native_jump(emit_t *emit, mp_uint_t label) {
emit_post(emit);
}
STATIC void emit_native_jump_helper(emit_t *emit, mp_uint_t label, bool pop) {
STATIC void emit_native_jump_helper(emit_t *emit, bool pop) {
vtype_kind_t vtype = peek_vtype(emit, 0);
switch (vtype) {
case VTYPE_PYOBJ:
@@ -1746,21 +1759,21 @@ STATIC void emit_native_jump_helper(emit_t *emit, mp_uint_t label, bool pop) {
STATIC void emit_native_pop_jump_if_true(emit_t *emit, mp_uint_t label) {
DEBUG_printf("pop_jump_if_true(label=" UINT_FMT ")\n", label);
emit_native_jump_helper(emit, label, true);
emit_native_jump_helper(emit, true);
ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
emit_post(emit);
}
STATIC void emit_native_pop_jump_if_false(emit_t *emit, mp_uint_t label) {
DEBUG_printf("pop_jump_if_false(label=" UINT_FMT ")\n", label);
emit_native_jump_helper(emit, label, true);
emit_native_jump_helper(emit, true);
ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
emit_post(emit);
}
STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
DEBUG_printf("jump_if_true_or_pop(label=" UINT_FMT ")\n", label);
emit_native_jump_helper(emit, label, false);
emit_native_jump_helper(emit, false);
ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
adjust_stack(emit, -1);
emit_post(emit);
@@ -1768,26 +1781,31 @@ STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, mp_uint_t label) {
STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, mp_uint_t label) {
DEBUG_printf("jump_if_false_or_pop(label=" UINT_FMT ")\n", label);
emit_native_jump_helper(emit, label, false);
emit_native_jump_helper(emit, false);
ASM_JUMP_IF_REG_ZERO(emit->as, REG_RET, label);
adjust_stack(emit, -1);
emit_post(emit);
}
STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
(void)except_depth;
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
}
STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
(void)except_depth;
emit_native_jump(emit, label); // TODO properly
}
STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
// not supported, or could be with runtime call
(void)emit;
(void)label;
assert(0);
}
STATIC void emit_native_with_cleanup(emit_t *emit) {
(void)emit;
assert(0);
}
@@ -1806,7 +1824,14 @@ STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) {
}
STATIC void emit_native_end_finally(emit_t *emit) {
emit_pre_pop_discard(emit);
// logic:
// exc = pop_stack
// if exc == None: pass
// else: raise exc
// the check if exc is None is done in the MP_F_NATIVE_RAISE stub
vtype_kind_t vtype;
emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
emit_call(emit, MP_F_NATIVE_RAISE);
emit_post(emit);
}
@@ -1847,6 +1872,7 @@ STATIC void emit_native_pop_block(emit_t *emit) {
}
STATIC void emit_native_pop_except(emit_t *emit) {
(void)emit;
/*
emit_native_pre(emit);
emit_call(emit, MP_F_NLR_POP);
@@ -2141,6 +2167,11 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_
}
STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
(void)emit;
(void)scope;
(void)n_closed_over;
(void)n_pos_defaults;
(void)n_kw_defaults;
assert(0);
}
@@ -2158,7 +2189,7 @@ STATIC void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u
// casting operator
assert(n_positional == 1 && n_keyword == 0);
DEBUG_printf(" cast to %d\n", vtype_fun);
vtype_kind_t vtype_cast = peek_stack(emit, 1)->u_imm;
vtype_kind_t vtype_cast = peek_stack(emit, 1)->data.u_imm;
switch (peek_vtype(emit, 0)) {
case VTYPE_PYOBJ: {
vtype_kind_t vtype;
@@ -2240,10 +2271,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
STATIC void emit_native_yield_value(emit_t *emit) {
// not supported (for now)
(void)emit;
assert(0);
}
STATIC void emit_native_yield_from(emit_t *emit) {
// not supported (for now)
(void)emit;
assert(0);
}
@@ -2283,6 +2316,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_load_const_int,
emit_native_load_const_dec,
emit_native_load_const_str,
emit_native_load_const_obj,
emit_native_load_null,
emit_native_load_fast,
emit_native_load_deref,

View File

@@ -24,20 +24,9 @@
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
#include "py/emit.h"
struct _emit_t {
scope_t *scope;
@@ -53,6 +42,7 @@ void emit_pass1_free(emit_t *emit) {
}
STATIC void emit_pass1_dummy(emit_t *emit) {
(void)emit;
}
STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
@@ -61,9 +51,11 @@ STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope
}
STATIC void emit_pass1_end_pass(emit_t *emit) {
(void)emit;
}
STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
(void)emit;
return false;
}
@@ -201,6 +193,7 @@ const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
#if MICROPY_PY_BUILTINS_SET
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,

View File

@@ -42,10 +42,11 @@
#include <stdlib.h>
#include <stdint.h>
#include "mpconfig.h"
#include "py/mpconfig.h"
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#include "formatfloat.h"
#include "py/formatfloat.h"
// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
@@ -63,7 +64,7 @@ static const float g_neg_pow[] = {
1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
};
int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
int mp_format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
char *s = buf;
int buf_remaining = buf_size - 1;

View File

@@ -23,5 +23,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_FORMATFLOAT_H__
#define __MICROPY_INCLUDED_PY_FORMATFLOAT_H__
int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
int mp_format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
#endif // __MICROPY_INCLUDED_PY_FORMATFLOAT_H__

53
py/frozenmod.c Normal file
View File

@@ -0,0 +1,53 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Paul Sokolovsky
*
* 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 <string.h>
#include <stdint.h>
#include "py/lexer.h"
#if MICROPY_MODULE_FROZEN
extern const uint16_t mp_frozen_sizes[];
extern const char mp_frozen_content[];
mp_lexer_t *mp_find_frozen_module(const char *str, int len) {
const uint16_t *sz_ptr = mp_frozen_sizes;
const char *s = mp_frozen_content;
while (*sz_ptr) {
int l = strlen(s);
if (l == len && !memcmp(str, s, l)) {
s += l + 1;
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR_, s, *sz_ptr, 0);
return lex;
}
s += l + 1 + *sz_ptr++;
}
return NULL;
}
#endif // MICROPY_MODULE_FROZEN

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,4 +24,4 @@
* THE SOFTWARE.
*/
mp_obj_t mp_obj_new_bytearray(mp_uint_t n, void *items);
mp_lexer_t *mp_find_frozen_module(const char *str, int len);

203
py/gc.c
View File

@@ -27,16 +27,11 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "gc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "py/mpstate.h"
#include "py/gc.h"
#include "py/obj.h"
#include "py/runtime.h"
#if MICROPY_ENABLE_GC
@@ -53,26 +48,6 @@
#define WORDS_PER_BLOCK (4)
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
#define STACK_SIZE (64) // tunable; minimum is 1
STATIC byte *gc_alloc_table_start;
STATIC mp_uint_t gc_alloc_table_byte_len;
#if MICROPY_ENABLE_FINALISER
STATIC byte *gc_finaliser_table_start;
#endif
// We initialise gc_pool_start to a dummy value so it stays out of the bss
// section. This makes sure we don't trace this pointer in a collect cycle.
// If we did trace it, it would make the first block of the heap always
// reachable, and hence we can never free that block.
STATIC mp_uint_t *gc_pool_start = (void*)4;
STATIC mp_uint_t *gc_pool_end;
STATIC int gc_stack_overflow;
STATIC mp_uint_t gc_stack[STACK_SIZE];
STATIC mp_uint_t *gc_sp;
STATIC uint16_t gc_lock_depth;
uint16_t gc_auto_collect_enabled;
STATIC mp_uint_t gc_last_free_atb_index;
// ATB = allocation table byte
// 0b00 = FREE -- free block
@@ -97,15 +72,15 @@ STATIC mp_uint_t gc_last_free_atb_index;
#define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0)
#define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1)))
#define ATB_GET_KIND(block) ((gc_alloc_table_start[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)
#define ATB_ANY_TO_FREE(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0)
#define ATB_FREE_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0)
#define ATB_FREE_TO_TAIL(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0)
#define ATB_HEAD_TO_MARK(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
#define ATB_MARK_TO_HEAD(block) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
#define ATB_GET_KIND(block) ((MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] >> BLOCK_SHIFT(block)) & 3)
#define ATB_ANY_TO_FREE(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_MARK << BLOCK_SHIFT(block))); } while (0)
#define ATB_FREE_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_HEAD << BLOCK_SHIFT(block)); } while (0)
#define ATB_FREE_TO_TAIL(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_TAIL << BLOCK_SHIFT(block)); } while (0)
#define ATB_HEAD_TO_MARK(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
#define ATB_MARK_TO_HEAD(block) do { MP_STATE_MEM(gc_alloc_table_start)[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)gc_pool_start))
#define BLOCK_FROM_PTR(ptr) (((ptr) - (mp_uint_t)MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK)
#define PTR_FROM_BLOCK(block) (((block) * BYTES_PER_BLOCK + (mp_uint_t)MP_STATE_MEM(gc_pool_start)))
#define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB)
#if MICROPY_ENABLE_FINALISER
@@ -114,9 +89,9 @@ STATIC mp_uint_t gc_last_free_atb_index;
#define BLOCKS_PER_FTB (8)
#define FTB_GET(block) ((gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
#define FTB_SET(block) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
#define FTB_CLEAR(block) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
#define FTB_GET(block) ((MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
#define FTB_SET(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
#define FTB_CLEAR(block) do { MP_STATE_MEM(gc_finaliser_table_start)[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
#endif
// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
@@ -132,67 +107,67 @@ void gc_init(void *start, void *end) {
// => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
mp_uint_t total_byte_len = (byte*)end - (byte*)start;
#if MICROPY_ENABLE_FINALISER
gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK);
#else
gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
MP_STATE_MEM(gc_alloc_table_byte_len) = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK);
#endif
gc_alloc_table_start = (byte*)start;
MP_STATE_MEM(gc_alloc_table_start) = (byte*)start;
#if MICROPY_ENABLE_FINALISER
mp_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len;
mp_uint_t gc_finaliser_table_byte_len = (MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB + BLOCKS_PER_FTB - 1) / BLOCKS_PER_FTB;
MP_STATE_MEM(gc_finaliser_table_start) = MP_STATE_MEM(gc_alloc_table_start) + MP_STATE_MEM(gc_alloc_table_byte_len);
#endif
mp_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
gc_pool_start = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
gc_pool_end = (mp_uint_t*)end;
mp_uint_t gc_pool_block_len = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
MP_STATE_MEM(gc_pool_start) = (mp_uint_t*)((byte*)end - gc_pool_block_len * BYTES_PER_BLOCK);
MP_STATE_MEM(gc_pool_end) = (mp_uint_t*)end;
#if MICROPY_ENABLE_FINALISER
assert((byte*)gc_pool_start >= gc_finaliser_table_start + gc_finaliser_table_byte_len);
assert((byte*)MP_STATE_MEM(gc_pool_start) >= MP_STATE_MEM(gc_finaliser_table_start) + gc_finaliser_table_byte_len);
#endif
// clear ATBs
memset(gc_alloc_table_start, 0, gc_alloc_table_byte_len);
memset(MP_STATE_MEM(gc_alloc_table_start), 0, MP_STATE_MEM(gc_alloc_table_byte_len));
#if MICROPY_ENABLE_FINALISER
// clear FTBs
memset(gc_finaliser_table_start, 0, gc_finaliser_table_byte_len);
memset(MP_STATE_MEM(gc_finaliser_table_start), 0, gc_finaliser_table_byte_len);
#endif
// set last free ATB index to start of heap
gc_last_free_atb_index = 0;
MP_STATE_MEM(gc_last_free_atb_index) = 0;
// unlock the GC
gc_lock_depth = 0;
MP_STATE_MEM(gc_lock_depth) = 0;
// allow auto collection
gc_auto_collect_enabled = 1;
MP_STATE_MEM(gc_auto_collect_enabled) = 1;
DEBUG_printf("GC layout:\n");
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_alloc_table_start, gc_alloc_table_byte_len, gc_alloc_table_byte_len * BLOCKS_PER_ATB);
DEBUG_printf(" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_alloc_table_start), MP_STATE_MEM(gc_alloc_table_byte_len), MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB);
#if MICROPY_ENABLE_FINALISER
DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_finaliser_table_start, gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
DEBUG_printf(" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_finaliser_table_start), gc_finaliser_table_byte_len, gc_finaliser_table_byte_len * BLOCKS_PER_FTB);
#endif
DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", gc_pool_start, gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
DEBUG_printf(" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n", MP_STATE_MEM(gc_pool_start), gc_pool_block_len * BYTES_PER_BLOCK, gc_pool_block_len);
}
void gc_lock(void) {
gc_lock_depth++;
MP_STATE_MEM(gc_lock_depth)++;
}
void gc_unlock(void) {
gc_lock_depth--;
MP_STATE_MEM(gc_lock_depth)--;
}
bool gc_is_locked(void) {
return gc_lock_depth != 0;
return MP_STATE_MEM(gc_lock_depth) != 0;
}
#define VERIFY_PTR(ptr) ( \
(ptr & (BYTES_PER_BLOCK - 1)) == 0 /* must be aligned on a block */ \
&& ptr >= (mp_uint_t)gc_pool_start /* must be above start of pool */ \
&& ptr < (mp_uint_t)gc_pool_end /* must be below end of pool */ \
&& ptr >= (mp_uint_t)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \
&& ptr < (mp_uint_t)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
)
#define VERIFY_MARK_AND_PUSH(ptr) \
@@ -202,19 +177,19 @@ bool gc_is_locked(void) {
if (ATB_GET_KIND(_block) == AT_HEAD) { \
/* an unmarked head, mark it, and push it on gc stack */ \
ATB_HEAD_TO_MARK(_block); \
if (gc_sp < &gc_stack[STACK_SIZE]) { \
*gc_sp++ = _block; \
if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \
*MP_STATE_MEM(gc_sp)++ = _block; \
} else { \
gc_stack_overflow = 1; \
MP_STATE_MEM(gc_stack_overflow) = 1; \
} \
} \
} \
} while (0)
STATIC void gc_drain_stack(void) {
while (gc_sp > gc_stack) {
while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) {
// pop the next block off the stack
mp_uint_t block = *--gc_sp;
mp_uint_t block = *--MP_STATE_MEM(gc_sp);
// work out number of consecutive blocks in the chain starting with this one
mp_uint_t n_blocks = 0;
@@ -232,15 +207,15 @@ STATIC void gc_drain_stack(void) {
}
STATIC void gc_deal_with_stack_overflow(void) {
while (gc_stack_overflow) {
gc_stack_overflow = 0;
gc_sp = gc_stack;
while (MP_STATE_MEM(gc_stack_overflow)) {
MP_STATE_MEM(gc_stack_overflow) = 0;
MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
// scan entire memory looking for blocks which have been marked but not their children
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
for (mp_uint_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
// trace (again) if mark bit set
if (ATB_GET_KIND(block) == AT_MARK) {
*gc_sp++ = block;
*MP_STATE_MEM(gc_sp)++ = block;
gc_drain_stack();
}
}
@@ -257,7 +232,7 @@ STATIC void gc_sweep(void) {
#endif
// free unmarked heads and their tails
int free_tail = 0;
for (mp_uint_t block = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
for (mp_uint_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
switch (ATB_GET_KIND(block)) {
case AT_HEAD:
#if MICROPY_ENABLE_FINALISER
@@ -299,8 +274,13 @@ STATIC void gc_sweep(void) {
void gc_collect_start(void) {
gc_lock();
gc_stack_overflow = 0;
gc_sp = gc_stack;
MP_STATE_MEM(gc_stack_overflow) = 0;
MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
// Trace root pointers. This relies on the root pointers being organised
// correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
// dict_globals, then the root pointer section of mp_state_vm.
void **ptrs = (void**)(void*)&mp_state_ctx;
gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t));
}
void gc_collect_root(void **ptrs, mp_uint_t len) {
@@ -314,18 +294,18 @@ void gc_collect_root(void **ptrs, mp_uint_t len) {
void gc_collect_end(void) {
gc_deal_with_stack_overflow();
gc_sweep();
gc_last_free_atb_index = 0;
MP_STATE_MEM(gc_last_free_atb_index) = 0;
gc_unlock();
}
void gc_info(gc_info_t *info) {
info->total = (gc_pool_end - gc_pool_start) * sizeof(mp_uint_t);
info->total = (MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start)) * sizeof(mp_uint_t);
info->used = 0;
info->free = 0;
info->num_1block = 0;
info->num_2block = 0;
info->max_block = 0;
for (mp_uint_t block = 0, len = 0; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB; block++) {
for (mp_uint_t block = 0, len = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
mp_uint_t kind = ATB_GET_KIND(block);
if (kind == AT_FREE || kind == AT_HEAD) {
if (len == 1) {
@@ -368,7 +348,7 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
DEBUG_printf("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n", n_bytes, n_blocks);
// check if GC is locked
if (gc_lock_depth > 0) {
if (MP_STATE_MEM(gc_lock_depth) > 0) {
return NULL;
}
@@ -381,12 +361,12 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
mp_uint_t end_block;
mp_uint_t start_block;
mp_uint_t n_free = 0;
int collected = !gc_auto_collect_enabled;
int collected = !MP_STATE_MEM(gc_auto_collect_enabled);
for (;;) {
// look for a run of n_blocks available blocks
for (i = gc_last_free_atb_index; i < gc_alloc_table_byte_len; i++) {
byte a = gc_alloc_table_start[i];
for (i = MP_STATE_MEM(gc_last_free_atb_index); i < MP_STATE_MEM(gc_alloc_table_byte_len); i++) {
byte a = MP_STATE_MEM(gc_alloc_table_start)[i];
if (ATB_0_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 0; goto found; } } else { n_free = 0; }
if (ATB_1_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 1; goto found; } } else { n_free = 0; }
if (ATB_2_IS_FREE(a)) { if (++n_free >= n_blocks) { i = i * BLOCKS_PER_ATB + 2; goto found; } } else { n_free = 0; }
@@ -414,7 +394,7 @@ found:
// before this one. Also, whenever we free or shink a block we must check
// if this index needs adjusting (see gc_realloc and gc_free).
if (n_free == 1) {
gc_last_free_atb_index = (i + 1) / BLOCKS_PER_ATB;
MP_STATE_MEM(gc_last_free_atb_index) = (i + 1) / BLOCKS_PER_ATB;
}
// mark first block as used head
@@ -427,7 +407,7 @@ found:
}
// get pointer to first block
void *ret_ptr = (void*)(gc_pool_start + start_block * WORDS_PER_BLOCK);
void *ret_ptr = (void*)(MP_STATE_MEM(gc_pool_start) + start_block * WORDS_PER_BLOCK);
DEBUG_printf("gc_alloc(%p)\n", ret_ptr);
// zero out the additional bytes of the newly allocated blocks
@@ -465,7 +445,7 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
// force the freeing of a piece of memory
void gc_free(void *ptr_in) {
if (gc_lock_depth > 0) {
if (MP_STATE_MEM(gc_lock_depth) > 0) {
// TODO how to deal with this error?
return;
}
@@ -477,8 +457,8 @@ void gc_free(void *ptr_in) {
mp_uint_t block = BLOCK_FROM_PTR(ptr);
if (ATB_GET_KIND(block) == AT_HEAD) {
// set the last_free pointer to this block if it's earlier in the heap
if (block / BLOCKS_PER_ATB < gc_last_free_atb_index) {
gc_last_free_atb_index = block / BLOCKS_PER_ATB;
if (block / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
MP_STATE_MEM(gc_last_free_atb_index) = block / BLOCKS_PER_ATB;
}
// free head and all of its tail blocks
@@ -547,7 +527,7 @@ void *gc_realloc(void *ptr, mp_uint_t n_bytes) {
#else // Alternative gc_realloc impl
void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
if (gc_lock_depth > 0) {
if (MP_STATE_MEM(gc_lock_depth) > 0) {
return NULL;
}
@@ -588,7 +568,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
// efficiently shrink it (see below for shrinking code).
mp_uint_t n_free = 0;
mp_uint_t n_blocks = 1; // counting HEAD block
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
mp_uint_t max_block = MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB;
for (mp_uint_t bl = block + n_blocks; bl < max_block; bl++) {
byte block_type = ATB_GET_KIND(bl);
if (block_type == AT_TAIL) {
@@ -619,8 +599,8 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
}
// set the last_free pointer to end of this block if it's earlier in the heap
if ((block + new_blocks) / BLOCKS_PER_ATB < gc_last_free_atb_index) {
gc_last_free_atb_index = (block + new_blocks) / BLOCKS_PER_ATB;
if ((block + new_blocks) / BLOCKS_PER_ATB < MP_STATE_MEM(gc_last_free_atb_index)) {
MP_STATE_MEM(gc_last_free_atb_index) = (block + new_blocks) / BLOCKS_PER_ATB;
}
#if EXTENSIVE_HEAP_PROFILING
@@ -669,7 +649,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
}
#endif // Alternative gc_realloc impl
void gc_dump_info() {
void gc_dump_info(void) {
gc_info_t info;
gc_info(&info);
printf("GC: total: " UINT_FMT ", used: " UINT_FMT ", free: " UINT_FMT "\n", info.total, info.used, info.free);
@@ -682,22 +662,22 @@ void gc_dump_alloc_table(void) {
#if !EXTENSIVE_HEAP_PROFILING
// When comparing heap output we don't want to print the starting
// pointer of the heap because it changes from run to run.
printf("GC memory layout; from %p:", gc_pool_start);
printf("GC memory layout; from %p:", MP_STATE_MEM(gc_pool_start));
#endif
for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {
for (mp_uint_t bl = 0; bl < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; bl++) {
if (bl % DUMP_BYTES_PER_LINE == 0) {
// a new line of blocks
{
// check if this line contains only free blocks
mp_uint_t bl2 = bl;
while (bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
while (bl2 < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) {
bl2++;
}
if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) {
// there are at least 2 lines containing only free blocks, so abbreviate their printing
printf("\n (" UINT_FMT " lines all free)", (bl2 - bl) / DUMP_BYTES_PER_LINE);
bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1));
if (bl >= gc_alloc_table_byte_len * BLOCKS_PER_ATB) {
if (bl >= MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB) {
// got to end of heap
break;
}
@@ -715,11 +695,9 @@ void gc_dump_alloc_table(void) {
case AT_FREE: c = '.'; break;
/* this prints out if the object is reachable from BSS or STACK (for unix only)
case AT_HEAD: {
extern char __bss_start, _end;
extern char *stack_top;
c = 'h';
void **ptrs = (void**)&__bss_start;
mp_uint_t len = ((mp_uint_t)&_end - (mp_uint_t)&__bss_start) / sizeof(mp_uint_t);
void **ptrs = (void**)(void*)&mp_state_ctx;
mp_uint_t len = offsetof(mp_state_ctx_t, vm.stack_top) / sizeof(mp_uint_t);
for (mp_uint_t i = 0; i < len; i++) {
mp_uint_t ptr = (mp_uint_t)ptrs[i];
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
@@ -729,7 +707,7 @@ void gc_dump_alloc_table(void) {
}
if (c == 'h') {
ptrs = (void**)&c;
len = ((mp_uint_t)stack_top - (mp_uint_t)&c) / sizeof(mp_uint_t);
len = ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)&c) / sizeof(mp_uint_t);
for (mp_uint_t i = 0; i < len; i++) {
mp_uint_t ptr = (mp_uint_t)ptrs[i];
if (VERIFY_PTR(ptr) && BLOCK_FROM_PTR(ptr) == bl) {
@@ -743,7 +721,7 @@ void gc_dump_alloc_table(void) {
*/
/* this prints the uPy object type of the head block */
case AT_HEAD: {
mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK;
mp_uint_t *ptr = MP_STATE_MEM(gc_pool_start) + bl * WORDS_PER_BLOCK;
if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; }
else if (*ptr == (mp_uint_t)&mp_type_list) { c = 'L'; }
else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; }
@@ -752,7 +730,26 @@ void gc_dump_alloc_table(void) {
#endif
else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; }
else if (*ptr == (mp_uint_t)&mp_type_module) { c = 'M'; }
else { c = 'h'; }
else {
c = 'h';
#if 0
// This code prints "Q" for qstr-pool data, and "q" for qstr-str
// data. It can be useful to see how qstrs are being allocated,
// but is disabled by default because it is very slow.
for (qstr_pool_t *pool = MP_STATE_VM(last_pool); c == 'h' && pool != NULL; pool = pool->prev) {
if ((qstr_pool_t*)ptr == pool) {
c = 'Q';
break;
}
for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) {
if ((const byte*)ptr == *q) {
c = 'q';
break;
}
}
}
#endif
}
break;
}
case AT_TAIL: c = 't'; break;

14
py/gc.h
View File

@@ -23,6 +23,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_GC_H__
#define __MICROPY_INCLUDED_PY_GC_H__
#include <stdint.h>
#include "py/mpconfig.h"
#include "py/misc.h"
void gc_init(void *start, void *end);
@@ -32,11 +39,6 @@ void gc_lock(void);
void gc_unlock(void);
bool gc_is_locked(void);
// This variable controls auto garbage collection. If set to 0 then the
// GC won't automatically run when gc_alloc can't find enough blocks. But
// you can still allocate/free memory and also explicitly call gc_collect.
extern uint16_t gc_auto_collect_enabled;
// A given port must implement gc_collect by using the other collect functions.
void gc_collect(void);
void gc_collect_start(void);
@@ -60,3 +62,5 @@ typedef struct _gc_info_t {
void gc_info(gc_info_t *info);
void gc_dump_info(void);
void gc_dump_alloc_table(void);
#endif // __MICROPY_INCLUDED_PY_GC_H__

View File

@@ -24,26 +24,17 @@
* THE SOFTWARE.
*/
/* lexer.c -- simple tokeniser for Python implementation
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "py/mpstate.h"
#include "py/lexer.h"
#define TAB_SIZE (8)
// TODO seems that CPython allows NULL byte in the input stream
// don't know if that's intentional or not, but we don't allow it
mp_uint_t mp_optimise_value;
// TODO replace with a call to a standard function
STATIC bool str_strn_equal(const char *str, const char *strn, mp_uint_t len) {
mp_uint_t i = 0;
@@ -666,11 +657,11 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) {
// need to check for this special token in many places in the compiler.
// TODO improve speed of these string comparisons
//for (mp_int_t i = 0; tok_kw[i] != NULL; i++) {
for (mp_int_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
for (size_t i = 0; i < MP_ARRAY_SIZE(tok_kw); i++) {
if (str_strn_equal(tok_kw[i], lex->vstr.buf, lex->vstr.len)) {
if (i == MP_ARRAY_SIZE(tok_kw) - 1) {
// tok_kw[MP_ARRAY_SIZE(tok_kw) - 1] == "__debug__"
lex->tok_kind = (mp_optimise_value == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
lex->tok_kind = (MP_STATE_VM(mp_optimise_value) == 0 ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE);
} else {
lex->tok_kind = MP_TOKEN_KW_FALSE + i;
}

View File

@@ -26,6 +26,11 @@
#ifndef __MICROPY_INCLUDED_PY_LEXER_H__
#define __MICROPY_INCLUDED_PY_LEXER_H__
#include <stdint.h>
#include "py/mpconfig.h"
#include "py/qstr.h"
/* lexer.h -- simple tokeniser for Micro Python
*
* Uses (byte) length instead of null termination.
@@ -187,6 +192,4 @@ typedef enum {
mp_import_stat_t mp_import_stat(const char *path);
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
extern mp_uint_t mp_optimise_value;
#endif // __MICROPY_INCLUDED_PY_LEXER_H__

View File

@@ -24,12 +24,7 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "lexer.h"
#include "py/lexer.h"
typedef struct _mp_lexer_str_buf_t {
mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len)

View File

@@ -24,8 +24,7 @@
* THE SOFTWARE.
*/
#include "mpconfig.h"
#include "misc.h"
#include "py/mpconfig.h"
#if MICROPY_HELPER_LEXER_UNIX
@@ -36,9 +35,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "qstr.h"
#include "lexer.h"
#include "lexerunix.h"
#include "py/lexer.h"
typedef struct _mp_lexer_file_buf_t {
int fd;

View File

@@ -13,14 +13,22 @@ elif platform.python_version_tuple()[0] == '3':
codepoint2name[ord('-')] = 'hyphen';
# add some custom names to map characters that aren't in HTML
codepoint2name[ord(' ')] = 'space'
codepoint2name[ord('\'')] = 'squot'
codepoint2name[ord(',')] = 'comma'
codepoint2name[ord('.')] = 'dot'
codepoint2name[ord(':')] = 'colon'
codepoint2name[ord('/')] = 'slash'
codepoint2name[ord('%')] = 'percent'
codepoint2name[ord('#')] = 'hash'
codepoint2name[ord('(')] = 'paren_open'
codepoint2name[ord(')')] = 'paren_close'
codepoint2name[ord('[')] = 'bracket_open'
codepoint2name[ord(']')] = 'bracket_close'
codepoint2name[ord('{')] = 'brace_open'
codepoint2name[ord('}')] = 'brace_close'
codepoint2name[ord('*')] = 'star'
codepoint2name[ord('!')] = 'bang'
# this must match the equivalent function in qstr.c
def compute_hash(qstr):
@@ -32,12 +40,25 @@ def compute_hash(qstr):
def do_work(infiles):
# read the qstrs in from the input files
qcfgs = {}
qstrs = {}
for infile in infiles:
with open(infile, 'rt') as f:
for line in f:
line = line.strip()
# is this a config line?
match = re.match(r'^QCFG\((.+), (.+)\)', line)
if match:
value = match.group(2)
if value[0] == '(' and value[-1] == ')':
# strip parenthesis from config value
value = value[1:-1]
qcfgs[match.group(1)] = value
continue
# is this a QSTR line?
match = re.match(r'^Q\((.+)\)$', line.strip())
match = re.match(r'^Q\((.*)\)$', line)
if not match:
continue
@@ -52,13 +73,27 @@ def do_work(infiles):
# add the qstr to the list, with order number to retain original order in file
qstrs[ident] = (len(qstrs), ident, qstr)
# process the qstrs, printing out the generated C header file
# get config variables
cfg_bytes_len = int(qcfgs['BYTES_IN_LEN'])
cfg_max_len = 1 << (8 * cfg_bytes_len)
# print out the starte of the generated C header file
print('// This file was automatically generated by makeqstrdata.py')
print('')
# add NULL qstr with no hash or data
print('QDEF(MP_QSTR_NULL, (const byte*)"\\x00\\x00%s" "")' % ('\\x00' * cfg_bytes_len))
# go through each qstr and print it out
for order, ident, qstr in sorted(qstrs.values(), key=lambda x: x[0]):
qhash = compute_hash(qstr)
qlen = len(qstr)
print('Q(%s, (const byte*)"\\x%02x\\x%02x\\x%02x\\x%02x" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, qstr))
qdata = qstr.replace('"', '\\"')
if qlen >= cfg_max_len:
print('qstr is too long:', qstr)
assert False
qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(((qlen >> (8 * i)) & 0xff) for i in range(cfg_bytes_len))
print('QDEF(MP_QSTR_%s, (const byte*)"\\x%02x\\x%02x%s" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen_str, qdata))
return True

View File

@@ -27,10 +27,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py/mpstate.h"
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
@@ -39,15 +39,11 @@
#endif
#if MICROPY_MEM_STATS
STATIC size_t total_bytes_allocated = 0;
STATIC size_t current_bytes_allocated = 0;
STATIC size_t peak_bytes_allocated = 0;
#define UPDATE_PEAK() { if (current_bytes_allocated > peak_bytes_allocated) peak_bytes_allocated = current_bytes_allocated; }
#define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); }
#endif
#if MICROPY_ENABLE_GC
#include "gc.h"
#include "py/gc.h"
// We redirect standard alloc functions to GC heap - just for the rest of
// this module. In the rest of micropython source, system malloc can be
@@ -69,8 +65,8 @@ void *m_malloc(size_t num_bytes) {
return m_malloc_fail(num_bytes);
}
#if MICROPY_MEM_STATS
total_bytes_allocated += num_bytes;
current_bytes_allocated += num_bytes;
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
UPDATE_PEAK();
#endif
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
@@ -80,8 +76,8 @@ void *m_malloc(size_t num_bytes) {
void *m_malloc_maybe(size_t num_bytes) {
void *ptr = malloc(num_bytes);
#if MICROPY_MEM_STATS
total_bytes_allocated += num_bytes;
current_bytes_allocated += num_bytes;
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
UPDATE_PEAK();
#endif
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
@@ -95,8 +91,8 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
return m_malloc_fail(num_bytes);
}
#if MICROPY_MEM_STATS
total_bytes_allocated += num_bytes;
current_bytes_allocated += num_bytes;
MP_STATE_MEM(total_bytes_allocated) += num_bytes;
MP_STATE_MEM(current_bytes_allocated) += num_bytes;
UPDATE_PEAK();
#endif
DEBUG_printf("malloc %d : %p\n", num_bytes, ptr);
@@ -125,8 +121,8 @@ void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
// allocated total. If we process only positive increments,
// we'll count 3K.
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
MP_STATE_MEM(total_bytes_allocated) += diff;
MP_STATE_MEM(current_bytes_allocated) += diff;
UPDATE_PEAK();
#endif
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
@@ -144,8 +140,8 @@ void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
// Also, don't count failed reallocs.
if (!(new_ptr == NULL && new_num_bytes != 0)) {
size_t diff = new_num_bytes - old_num_bytes;
total_bytes_allocated += diff;
current_bytes_allocated += diff;
MP_STATE_MEM(total_bytes_allocated) += diff;
MP_STATE_MEM(current_bytes_allocated) += diff;
UPDATE_PEAK();
}
#endif
@@ -156,21 +152,21 @@ void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes) {
void m_free(void *ptr, size_t num_bytes) {
free(ptr);
#if MICROPY_MEM_STATS
current_bytes_allocated -= num_bytes;
MP_STATE_MEM(current_bytes_allocated) -= num_bytes;
#endif
DEBUG_printf("free %p, %d\n", ptr, num_bytes);
}
#if MICROPY_MEM_STATS
size_t m_get_total_bytes_allocated(void) {
return total_bytes_allocated;
return MP_STATE_MEM(total_bytes_allocated);
}
size_t m_get_current_bytes_allocated(void) {
return current_bytes_allocated;
return MP_STATE_MEM(current_bytes_allocated);
}
size_t m_get_peak_bytes_allocated(void) {
return peak_bytes_allocated;
return MP_STATE_MEM(peak_bytes_allocated);
}
#endif

View File

@@ -28,11 +28,9 @@
#include <stdlib.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py/obj.h"
// Fixed empty map. Useful when need to call kw-receiving functions
// without any keywords from C, etc.
@@ -49,7 +47,7 @@ const mp_map_t mp_const_empty_map = {
STATIC uint32_t doubling_primes[] = {0, 7, 19, 43, 89, 179, 347, 647, 1229, 2297, 4243, 7829, 14347, 26017, 47149, 84947, 152443, 273253, 488399, 869927, 1547173, 2745121, 4861607};
STATIC mp_uint_t get_doubling_prime_greater_or_equal_to(mp_uint_t x) {
for (int i = 0; i < MP_ARRAY_SIZE(doubling_primes); i++) {
for (size_t i = 0; i < MP_ARRAY_SIZE(doubling_primes); i++) {
if (doubling_primes[i] >= x) {
return doubling_primes[i];
}

View File

@@ -23,12 +23,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_MISC_H__
#define __MICROPY_INCLUDED_PY_MISC_H__
// a mini library of useful types and functions
#ifndef _INCLUDED_MINILIB_H
#define _INCLUDED_MINILIB_H
/** types *******************************************************/
#include <stdbool.h>
@@ -125,6 +124,7 @@ typedef struct _vstr_t {
#define VSTR_FIXED(vstr, alloc) vstr_t vstr; char vstr##_buf[(alloc)]; vstr_init_fixed_buf(&vstr, (alloc), vstr##_buf);
void vstr_init(vstr_t *vstr, size_t alloc);
void vstr_init_len(vstr_t *vstr, size_t len);
void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf);
void vstr_clear(vstr_t *vstr);
vstr_t *vstr_new(void);
@@ -136,8 +136,6 @@ char *vstr_str(vstr_t *vstr);
size_t vstr_len(vstr_t *vstr);
void vstr_hint_size(vstr_t *vstr, size_t size);
char *vstr_extend(vstr_t *vstr, size_t size);
bool vstr_set_size(vstr_t *vstr, size_t size);
bool vstr_shrink(vstr_t *vstr);
char *vstr_add_len(vstr_t *vstr, size_t len);
void vstr_add_byte(vstr_t *vstr, byte v);
void vstr_add_char(vstr_t *vstr, unichar chr);
@@ -185,4 +183,17 @@ static inline mp_uint_t count_lead_ones(byte val) {
}
#endif
#endif // _INCLUDED_MINILIB_H
/** float internals *************/
#if MICROPY_PY_BUILTINS_FLOAT
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
#define MP_FLOAT_EXP_BITS (11)
#define MP_FLOAT_FRAC_BITS (52)
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#define MP_FLOAT_EXP_BITS (8)
#define MP_FLOAT_FRAC_BITS (23)
#endif
#define MP_FLOAT_EXP_BIAS ((1 << (MP_FLOAT_EXP_BITS - 1)) - 1)
#endif // MICROPY_PY_BUILTINS_FLOAT
#endif // __MICROPY_INCLUDED_PY_MISC_H__

View File

@@ -24,11 +24,7 @@
* THE SOFTWARE.
*/
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "py/builtin.h"
#if MICROPY_PY_ARRAY

View File

@@ -27,18 +27,14 @@
#include <stdio.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "objstr.h"
#include "smallint.h"
#include "runtime0.h"
#include "runtime.h"
#include "builtin.h"
#include "stream.h"
#include "pfenv.h"
#include "py/nlr.h"
#include "py/smallint.h"
#include "py/objstr.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/stream.h"
#include "py/pfenv.h"
#if MICROPY_PY_BUILTINS_FLOAT
#include <math.h>
@@ -145,7 +141,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_any_obj, mp_builtin_any);
STATIC mp_obj_t mp_builtin_bin(mp_obj_t o_in) {
mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR__brace_open__colon__hash_b_brace_close_), o_in };
return mp_obj_str_format(MP_ARRAY_SIZE(args), args);
return mp_obj_str_format(MP_ARRAY_SIZE(args), args, NULL);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_bin_obj, mp_builtin_bin);
@@ -410,6 +406,7 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
end_data = mp_obj_str_get_data(end_elem->value, &end_len);
}
#if MICROPY_PY_IO
extern mp_uint_t mp_sys_stdout_obj; // type is irrelevant, just need pointer
mp_obj_t stream_obj = &mp_sys_stdout_obj;
mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
if (file_elem != NULL && file_elem->value != mp_const_none) {
@@ -452,11 +449,10 @@ STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj, mp_builtin___repl_print__);
STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
vstr_t *vstr = vstr_new();
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, vstr, o_in, PRINT_REPR);
mp_obj_t s = mp_obj_new_str(vstr->buf, vstr->len, false);
vstr_free(vstr);
return s;
vstr_t vstr;
vstr_init(&vstr, 16);
mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))vstr_printf, &vstr, o_in, PRINT_REPR);
return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);

View File

@@ -24,16 +24,12 @@
* THE SOFTWARE.
*/
#include <math.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "py/builtin.h"
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_CMATH
#include <math.h>
/// \module cmath - mathematical functions for complex numbers
///
/// The `cmath` module provides some basic mathematical funtions for

View File

@@ -24,11 +24,7 @@
* THE SOFTWARE.
*/
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "py/builtin.h"
#if MICROPY_PY_COLLECTIONS

View File

@@ -24,14 +24,9 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "gc.h"
#include "py/mpstate.h"
#include "py/obj.h"
#include "py/gc.h"
#if MICROPY_PY_GC && MICROPY_ENABLE_GC
@@ -54,7 +49,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_collect_obj, py_gc_collect);
/// \function disable()
/// Disable the garbage collector.
STATIC mp_obj_t gc_disable(void) {
gc_auto_collect_enabled = 0;
MP_STATE_MEM(gc_auto_collect_enabled) = 0;
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
@@ -62,13 +57,13 @@ MP_DEFINE_CONST_FUN_OBJ_0(gc_disable_obj, gc_disable);
/// \function enable()
/// Enable the garbage collector.
STATIC mp_obj_t gc_enable(void) {
gc_auto_collect_enabled = 1;
MP_STATE_MEM(gc_auto_collect_enabled) = 1;
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_enable_obj, gc_enable);
STATIC mp_obj_t gc_isenabled(void) {
return MP_BOOL(gc_auto_collect_enabled);
return MP_BOOL(MP_STATE_MEM(gc_auto_collect_enabled));
}
MP_DEFINE_CONST_FUN_OBJ_0(gc_isenabled_obj, gc_isenabled);

View File

@@ -24,11 +24,7 @@
* THE SOFTWARE.
*/
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "py/builtin.h"
#if MICROPY_PY_IO

View File

@@ -24,16 +24,12 @@
* THE SOFTWARE.
*/
#include <math.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "py/builtin.h"
#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
#include <math.h>
/// \module math - mathematical functions
///
/// The `math` module provides some basic mathematical funtions for

View File

@@ -24,45 +24,54 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdio.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "stackctrl.h"
#include "gc.h"
#include "py/mpstate.h"
#include "py/builtin.h"
#include "py/stackctrl.h"
#include "py/gc.h"
// Various builtins specific to MicroPython runtime,
// living in micropython module
#if MICROPY_PY_MICROPYTHON_MEM_INFO
#if MICROPY_MEM_STATS
STATIC mp_obj_t mp_micropython_mem_total() {
STATIC mp_obj_t mp_micropython_mem_total(void) {
return MP_OBJ_NEW_SMALL_INT(m_get_total_bytes_allocated());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_total_obj, mp_micropython_mem_total);
STATIC mp_obj_t mp_micropython_mem_current() {
STATIC mp_obj_t mp_micropython_mem_current(void) {
return MP_OBJ_NEW_SMALL_INT(m_get_current_bytes_allocated());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_current_obj, mp_micropython_mem_current);
STATIC mp_obj_t mp_micropython_mem_peak() {
STATIC mp_obj_t mp_micropython_mem_peak(void) {
return MP_OBJ_NEW_SMALL_INT(m_get_peak_bytes_allocated());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_mem_peak_obj, mp_micropython_mem_peak);
#endif
mp_obj_t mp_micropython_mem_info(mp_uint_t n_args, const mp_obj_t *args) {
(void)args;
#if MICROPY_MEM_STATS
printf("mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n",
m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
#endif
#if MICROPY_STACK_CHECK
printf("stack: " UINT_FMT " out of " INT_FMT "\n", mp_stack_usage(), MP_STATE_VM(stack_limit));
#else
printf("stack: " UINT_FMT "\n", mp_stack_usage());
#endif
#if MICROPY_ENABLE_GC
gc_dump_info();
if (n_args == 1) {
// arg given means dump gc allocation table
gc_dump_alloc_table();
}
#else
(void)n_args;
#endif
return mp_const_none;
}
@@ -76,7 +85,8 @@ STATIC mp_obj_t qstr_info(void) {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_qstr_info_obj, qstr_info);
#endif
#endif // MICROPY_PY_MICROPYTHON_MEM_INFO
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_emergency_exception_buf);
@@ -84,10 +94,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_
STATIC const mp_map_elem_t mp_module_micropython_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_micropython) },
#if MICROPY_PY_MICROPYTHON_MEM_INFO
#if MICROPY_MEM_STATS
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_total), (mp_obj_t)&mp_micropython_mem_total_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_current), (mp_obj_t)&mp_micropython_mem_current_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_peak), (mp_obj_t)&mp_micropython_mem_peak_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_mem_info), (mp_obj_t)&mp_micropython_mem_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_qstr_info), (mp_obj_t)&mp_micropython_qstr_info_obj },
#endif

View File

@@ -27,15 +27,11 @@
#include <assert.h>
#include <string.h>
#include "mpconfig.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "objtuple.h"
#include "objstr.h"
#include "binary.h"
#include "parsenum.h"
#include "py/builtin.h"
#include "py/objtuple.h"
#include "py/binary.h"
#include "py/parsenum.h"
#if MICROPY_PY_STRUCT
@@ -165,8 +161,9 @@ STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
const char *fmt = mp_obj_str_get_str(args[0]);
char fmt_type = get_fmt_type(&fmt);
mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
byte *p;
mp_obj_t res = mp_obj_str_builder_start(&mp_type_bytes, size, &p);
vstr_t vstr;
vstr_init_len(&vstr, size);
byte *p = (byte*)vstr.buf;
memset(p, 0, size);
for (mp_uint_t i = 1; i < n_args; i++) {
@@ -194,7 +191,8 @@ STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
mp_binary_set_val(fmt_type, *fmt++, args[i], &p);
}
}
return res;
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);

View File

@@ -24,27 +24,24 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "builtin.h"
#include "runtime.h"
#include "objlist.h"
#include "objtuple.h"
#include "objstr.h"
#include "mpz.h"
#include "objint.h"
#include "pfenv.h"
#include "stream.h"
#include "py/nlr.h"
#include "py/builtin.h"
#include "py/objlist.h"
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/objint.h"
#include "py/pfenv.h"
#include "py/stream.h"
#if MICROPY_PY_SYS
/// \module sys - system specific functions
// defined per port; type of these is irrelevant, just need pointer
extern mp_uint_t mp_sys_stdin_obj;
extern mp_uint_t mp_sys_stdout_obj;
extern mp_uint_t mp_sys_stderr_obj;
// These two lists must be initialised per port (after the call to mp_init).
// TODO document these properly, they aren't constants or functions...
/// \constant path - a mutable list of directories to search for imported modules

View File

@@ -23,6 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_MPCONFIG_H__
#define __MICROPY_INCLUDED_PY_MPCONFIG_H__
// This file contains default configuration settings for MicroPython.
// You can override any of the options below using mpconfigport.h file
@@ -49,6 +51,11 @@
/*****************************************************************************/
/* Memory allocation policy */
// Number of words allocated (in BSS) to the GC stack (minimum is 1)
#ifndef MICROPY_ALLOC_GC_STACK_SIZE
#define MICROPY_ALLOC_GC_STACK_SIZE (64)
#endif
// Initial amount for lexer indentation level
#ifndef MICROPY_ALLOC_LEXER_INDENT_INIT
#define MICROPY_ALLOC_LEXER_INDENT_INIT (10)
@@ -105,6 +112,13 @@
#define MICROPY_MODULE_DICT_SIZE (1)
#endif
// Number of bytes used to store qstr length
// Dictates hard limit on maximum Python identifier length, but 1 byte
// (limit of 255 bytes in an identifier) should be enough for everyone
#ifndef MICROPY_QSTR_BYTES_IN_LEN
#define MICROPY_QSTR_BYTES_IN_LEN (1)
#endif
/*****************************************************************************/
/* Micro Python emitters */
@@ -145,6 +159,11 @@
/*****************************************************************************/
/* Compiler configuration */
// Whether to enable lookup of constants in modules; eg module.CONST
#ifndef MICROPY_COMP_MODULE_CONST
#define MICROPY_COMP_MODULE_CONST (0)
#endif
// Whether to enable constant optimisation; id = const(value)
#ifndef MICROPY_COMP_CONST
#define MICROPY_COMP_CONST (1)
@@ -175,6 +194,13 @@
#define MICROPY_OPT_COMPUTED_GOTO (0)
#endif
// Whether to cache result of map lookups in LOAD_NAME, LOAD_GLOBAL, LOAD_ATTR,
// STORE_ATTR bytecodes. Uses 1 byte extra RAM for each of these opcodes and
// uses a bit of extra code ROM, but greatly improves lookup speed.
#ifndef MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
#endif
/*****************************************************************************/
/* Python internal features */
@@ -191,7 +217,7 @@
// Whether to check C stack usage. C stack used for calling Python functions,
// etc. Not checking means segfault on overflow.
#ifndef MICROPY_STACK_CHECK
#define MICROPY_STACK_CHECK (1)
#define MICROPY_STACK_CHECK (0)
#endif
// Whether to have an emergency exception buffer
@@ -209,6 +235,11 @@
#define MICROPY_HELPER_REPL (0)
#endif
// Whether port requires event-driven REPL functions
#ifndef MICROPY_REPL_EVENT_DRIVEN
#define MICROPY_REPL_EVENT_DRIVEN (0)
#endif
// Whether to include lexer helper function for unix
#ifndef MICROPY_HELPER_LEXER_UNIX
#define MICROPY_HELPER_LEXER_UNIX (0)
@@ -249,6 +280,11 @@ typedef long long mp_longint_impl_t;
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#endif
// Whether issue warnings during compiling/execution
#ifndef MICROPY_WARNINGS
#define MICROPY_WARNINGS (0)
#endif
// Float and complex implementation
#define MICROPY_FLOAT_IMPL_NONE (0)
#define MICROPY_FLOAT_IMPL_FLOAT (1)
@@ -292,6 +328,11 @@ typedef double mp_float_t;
#define MICROPY_MODULE_WEAK_LINKS (0)
#endif
// Whether frozen modules are supported
#ifndef MICROPY_MODULE_FROZEN
#define MICROPY_MODULE_FROZEN (0)
#endif
// Whether you can override builtins in the builtins module
#ifndef MICROPY_CAN_OVERRIDE_BUILTINS
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
@@ -350,6 +391,11 @@ typedef double mp_float_t;
#define MICROPY_PY___FILE__ (1)
#endif
// Whether to provide mem-info related functions in micropython module
#ifndef MICROPY_PY_MICROPYTHON_MEM_INFO
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#endif
// Whether to provide "array" module. Note that large chunk of the
// underlying code is shared with "bytearray" builtin type, so to
// get real savings, it should be disabled too.
@@ -476,6 +522,11 @@ typedef double mp_float_t;
#define MICROPY_PORT_CONSTANTS
#endif
// Any root pointers for GC scanning - see mpstate.c
#ifndef MICROPY_PORT_ROOT_POINTERS
#define MICROPY_PORT_ROOT_POINTERS
#endif
/*****************************************************************************/
/* Miscellaneous settings */
@@ -528,6 +579,9 @@ typedef double mp_float_t;
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
#endif
// If these MP_PLAT_* macros are overridden then the memory allocated by them
// must be somehow reachable for marking by the GC, since the native code
// generators store pointers to GC managed memory in the code.
#ifndef MP_PLAT_ALLOC_EXEC
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while(0)
#endif
@@ -572,3 +626,5 @@ typedef double mp_float_t;
#ifndef MP_UNLIKELY
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
#endif
#endif // __MICROPY_INCLUDED_PY_MPCONFIG_H__

View File

@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,6 +24,6 @@
* THE SOFTWARE.
*/
mp_lexer_t *mp_lexer_new_from_file(const char *filename);
#include "py/mpstate.h"
void mp_import_set_directory(const char *dir);
mp_state_ctx_t mp_state_ctx;

156
py/mpstate.h Normal file
View File

@@ -0,0 +1,156 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* 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.
*/
#ifndef __MICROPY_INCLUDED_PY_MPSTATE_H__
#define __MICROPY_INCLUDED_PY_MPSTATE_H__
#include <stdint.h>
#include "py/mpconfig.h"
#include "py/misc.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/objlist.h" // in case port needs mp_obj_list_t in root pointers
#include "py/objexcept.h"
// This file contains structures defining the state of the Micro Python
// memory system, runtime and virtual machine. The state is a global
// variable, but in the future it is hoped that the state can become local.
// This structure hold information about the memory allocation system.
typedef struct _mp_state_mem_t {
#if MICROPY_MEM_STATS
size_t total_bytes_allocated;
size_t current_bytes_allocated;
size_t peak_bytes_allocated;
#endif
byte *gc_alloc_table_start;
mp_uint_t gc_alloc_table_byte_len;
#if MICROPY_ENABLE_FINALISER
byte *gc_finaliser_table_start;
#endif
mp_uint_t *gc_pool_start;
mp_uint_t *gc_pool_end;
int gc_stack_overflow;
mp_uint_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
mp_uint_t *gc_sp;
uint16_t gc_lock_depth;
// This variable controls auto garbage collection. If set to 0 then the
// GC won't automatically run when gc_alloc can't find enough blocks. But
// you can still allocate/free memory and also explicitly call gc_collect.
uint16_t gc_auto_collect_enabled;
mp_uint_t gc_last_free_atb_index;
} mp_state_mem_t;
// This structure hold runtime and VM information. It includes a section
// which contains root pointers that must be scanned by the GC.
typedef struct _mp_state_vm_t {
////////////////////////////////////////////////////////////
// START ROOT POINTER SECTION
// everything that needs GC scanning must go here
// this must start at the start of this structure
//
// Note: nlr asm code has the offset of this hard-coded
nlr_buf_t *nlr_top;
qstr_pool_t *last_pool;
// non-heap memory for creating an exception if we can't allocate RAM
mp_obj_exception_t mp_emergency_exception_obj;
// memory for exception arguments if we can't allocate RAM
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
#if MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE > 0
// statically allocated buf
byte mp_emergency_exception_buf[MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE];
#else
// dynamically allocated buf
byte *mp_emergency_exception_buf;
#endif
#endif
// map with loaded modules
// TODO: expose as sys.modules
mp_map_t mp_loaded_modules_map;
// pending exception object (MP_OBJ_NULL if not pending)
mp_obj_t mp_pending_exception;
// dictionary for the __main__ module
mp_obj_dict_t dict_main;
// dictionary for overridden builtins
#if MICROPY_CAN_OVERRIDE_BUILTINS
mp_obj_dict_t *mp_module_builtins_override_dict;
#endif
// include any root pointers defined by a port
MICROPY_PORT_ROOT_POINTERS
//
// END ROOT POINTER SECTION
////////////////////////////////////////////////////////////
// Stack top at the start of program
// Note: this entry is used to locate the end of the root pointer section.
char *stack_top;
#if MICROPY_STACK_CHECK
mp_uint_t stack_limit;
#endif
mp_uint_t mp_optimise_value;
// size of the emergency exception buf, if it's dynamically allocated
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0
mp_int_t mp_emergency_exception_buf_size;
#endif
} mp_state_vm_t;
// This structure combines the above 2 structures, and adds the local
// and global dicts.
// Note: if this structure changes then revisit all nlr asm code since they
// have the offset of nlr_top hard-coded.
typedef struct _mp_state_ctx_t {
// these must come first for root pointer scanning in GC to work
mp_obj_dict_t *dict_locals;
mp_obj_dict_t *dict_globals;
// this must come next for root pointer scanning in GC to work
mp_state_vm_t vm;
mp_state_mem_t mem;
} mp_state_ctx_t;
extern mp_state_ctx_t mp_state_ctx;
#define MP_STATE_CTX(x) (mp_state_ctx.x)
#define MP_STATE_VM(x) (mp_state_ctx.vm.x)
#define MP_STATE_MEM(x) (mp_state_ctx.mem.x)
#endif // __MICROPY_INCLUDED_PY_MPSTATE_H__

120
py/mpz.c
View File

@@ -24,15 +24,10 @@
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "misc.h"
#include "mpz.h"
#include "py/mpz.h"
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
@@ -203,10 +198,10 @@ STATIC mp_uint_t mpn_sub(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen,
/* computes i = j & k
returns number of digits in i
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen
assumes enough memory in i; assumes normalised j, k; assumes jlen >= klen (jlen argument not needed)
can have i, j, k pointing to same memory
*/
STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, mp_uint_t jlen, const mpz_dig_t *kdig, mp_uint_t klen) {
STATIC mp_uint_t mpn_and(mpz_dig_t *idig, const mpz_dig_t *jdig, const mpz_dig_t *kdig, mp_uint_t klen) {
mpz_dig_t *oidig = idig;
for (; klen > 0; --klen, ++idig, ++jdig, ++kdig) {
@@ -595,6 +590,14 @@ mpz_t *mpz_from_ll(long long val, bool is_signed) {
return z;
}
#if MICROPY_PY_BUILTINS_FLOAT
mpz_t *mpz_from_float(mp_float_t val) {
mpz_t *z = mpz_zero();
mpz_set_from_float(z, val);
return z;
}
#endif
mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
mpz_t *z = mpz_zero();
mpz_set_from_str(z, str, len, neg, base);
@@ -650,6 +653,11 @@ void mpz_set(mpz_t *dest, const mpz_t *src) {
}
void mpz_set_from_int(mpz_t *z, mp_int_t val) {
if (val == 0) {
z->len = 0;
return;
}
mpz_need_dig(z, MPZ_NUM_DIG_FOR_INT);
mp_uint_t uval;
@@ -687,6 +695,73 @@ void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
}
}
#if MICROPY_PY_BUILTINS_FLOAT
void mpz_set_from_float(mpz_t *z, mp_float_t src) {
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
typedef uint64_t mp_float_int_t;
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
typedef uint32_t mp_float_int_t;
#endif
union {
mp_float_t f;
struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
} u = {src};
z->neg = u.p.sgn;
if (u.p.exp == 0) {
// value == 0 || value < 1
mpz_set_from_int(z, 0);
} else if (u.p.exp == ((1 << MP_FLOAT_EXP_BITS) - 1)) {
// u.p.frc == 0 indicates inf, else NaN
// should be handled by caller
mpz_set_from_int(z, 0);
} else {
const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
if (adj_exp < 0) {
// value < 1 , truncates to 0
mpz_set_from_int(z, 0);
} else if (adj_exp == 0) {
// 1 <= value < 2 , so truncates to 1
mpz_set_from_int(z, 1);
} else {
// 2 <= value
const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
const unsigned int rem = adj_exp % DIG_SIZE;
int dig_ind, shft;
mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << MP_FLOAT_FRAC_BITS);
if (adj_exp < MP_FLOAT_FRAC_BITS) {
shft = 0;
dig_ind = 0;
frc >>= MP_FLOAT_FRAC_BITS - adj_exp;
} else {
shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE;
dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE;
}
mpz_need_dig(z, dig_cnt);
z->len = dig_cnt;
if (dig_ind != 0) {
memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
}
if (shft != 0) {
z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
frc >>= DIG_SIZE - shft;
}
#if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1)
while (dig_ind != dig_cnt) {
z->dig[dig_ind++] = frc & DIG_MASK;
frc >>= DIG_SIZE;
}
#else
if (dig_ind != dig_cnt) {
z->dig[dig_ind] = frc;
}
#endif
}
}
}
#endif
// returns number of bytes from str that were processed
mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
assert(base < 36);
@@ -871,11 +946,17 @@ void mpz_not_inpl(mpz_t *dest, const mpz_t *z) {
if (dest != z) {
mpz_set(dest, z);
}
if (dest->neg) {
if (dest->len == 0) {
mpz_need_dig(dest, 1);
dest->dig[0] = 1;
dest->len = 1;
dest->neg = 1;
} else if (dest->neg) {
dest->neg = 0;
mpz_dig_t k = 1;
dest->len = mpn_sub(dest->dig, dest->dig, dest->len, &k, 1);
} else {
mpz_need_dig(dest, dest->len + 1);
mpz_dig_t k = 1;
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &k, 1);
dest->neg = 1;
@@ -924,7 +1005,14 @@ void mpz_shr_inpl(mpz_t *dest, const mpz_t *lhs, mp_int_t rhs) {
round_up = 1;
}
if (round_up) {
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
if (dest->len == 0) {
// dest == 0, so need to add 1 by hand (answer will be -1)
dest->dig[0] = 1;
dest->len = 1;
} else {
// dest > 0, so can use mpn_add to add 1
dest->len = mpn_add(dest->dig, dest->dig, dest->len, &round_up, 1);
}
}
}
}
@@ -993,7 +1081,7 @@ void mpz_and_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
}
// do the and'ing
mpz_need_dig(dest, rhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, lhs->len, rhs->dig, rhs->len);
dest->len = mpn_and(dest->dig, lhs->dig, rhs->dig, rhs->len);
dest->neg = 0;
} else {
// TODO both args are negative
@@ -1270,7 +1358,7 @@ mp_int_t mpz_hash(const mpz_t *z) {
mp_int_t val = 0;
mpz_dig_t *d = z->dig + z->len;
while (--d >= z->dig) {
while (d-- > z->dig) {
val = (val << DIG_SIZE) | *d;
}
@@ -1282,10 +1370,10 @@ mp_int_t mpz_hash(const mpz_t *z) {
}
bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) {
mp_int_t val = 0;
mp_uint_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
while (d-- > i->dig) {
if (val > (~(WORD_MSBIT_HIGH) >> DIG_SIZE)) {
// will overflow
return false;
@@ -1310,7 +1398,7 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) {
mp_uint_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
while (d-- > i->dig) {
if (val > (~(WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) {
// will overflow
return false;
@@ -1327,7 +1415,7 @@ mp_float_t mpz_as_float(const mpz_t *i) {
mp_float_t val = 0;
mpz_dig_t *d = i->dig + i->len;
while (--d >= i->dig) {
while (d-- > i->dig) {
val = val * DIG_BASE + *d;
}

View File

@@ -23,6 +23,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_MPZ_H__
#define __MICROPY_INCLUDED_PY_MPZ_H__
#include <stdint.h>
#include "py/mpconfig.h"
#include "py/misc.h"
// This mpz module implements arbitrary precision integers.
//
@@ -62,7 +69,7 @@ typedef int32_t mpz_dbl_dig_signed_t;
typedef struct _mpz_t {
mp_uint_t neg : 1;
mp_uint_t fixed_dig : 1;
mp_uint_t alloc : 30;
mp_uint_t alloc : BITS_PER_WORD - 2;
mp_uint_t len;
mpz_dig_t *dig;
} mpz_t;
@@ -78,6 +85,9 @@ void mpz_deinit(mpz_t *z);
mpz_t *mpz_zero(void);
mpz_t *mpz_from_int(mp_int_t i);
mpz_t *mpz_from_ll(long long i, bool is_signed);
#if MICROPY_PY_BUILTINS_FLOAT
mpz_t *mpz_from_float(mp_float_t i);
#endif
mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base);
void mpz_free(mpz_t *z);
@@ -86,6 +96,9 @@ mpz_t *mpz_clone(const mpz_t *src);
void mpz_set(mpz_t *dest, const mpz_t *src);
void mpz_set_from_int(mpz_t *z, mp_int_t src);
void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed);
#if MICROPY_PY_BUILTINS_FLOAT
void mpz_set_from_float(mpz_t *z, mp_float_t src);
#endif
mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base);
bool mpz_is_zero(const mpz_t *z);
@@ -131,3 +144,5 @@ mp_float_t mpz_as_float(const mpz_t *z);
#endif
mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma);
mp_uint_t mpz_as_str_inpl(const mpz_t *z, mp_uint_t base, const char *prefix, char base_char, char comma, char *str);
#endif // __MICROPY_INCLUDED_PY_MPZ_H__

View File

@@ -28,14 +28,10 @@
#include <string.h>
#include <assert.h>
#include "mpconfig.h"
#include "nlr.h"
#include "misc.h"
#include "qstr.h"
#include "obj.h"
#include "runtime0.h"
#include "runtime.h"
#include "emitglue.h"
#include "py/nlr.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/emitglue.h"
#if MICROPY_EMIT_NATIVE
@@ -84,8 +80,11 @@ mp_obj_t mp_native_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args_kw, cons
}
// wrapper that makes raise obj and raises it
NORETURN void mp_native_raise(mp_obj_t o) {
nlr_raise(mp_make_raise_obj(o));
// END_FINALLY opcode requires that we don't raise if o==None
void mp_native_raise(mp_obj_t o) {
if (o != mp_const_none) {
nlr_raise(mp_make_raise_obj(o));
}
}
// these must correspond to the respective enum in runtime0.h

View File

@@ -23,6 +23,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __MICROPY_INCLUDED_PY_NLR_H__
#define __MICROPY_INCLUDED_PY_NLR_H__
// non-local return
// exception handling, basically a stack of setjmp/longjmp buffers
@@ -31,6 +33,8 @@
#include <setjmp.h>
#include <assert.h>
#include "py/mpconfig.h"
typedef struct _nlr_buf_t nlr_buf_t;
struct _nlr_buf_t {
// the entries here must all be machine word size
@@ -61,12 +65,13 @@ struct _nlr_buf_t {
};
#if MICROPY_NLR_SETJMP
extern nlr_buf_t *nlr_setjmp_top;
#include "py/mpstate.h"
NORETURN void nlr_setjmp_jump(void *val);
// nlr_push() must be defined as a macro, because "The stack context will be
// invalidated if the function which called setjmp() returns."
#define nlr_push(buf) ((buf)->prev = nlr_setjmp_top, nlr_setjmp_top = (buf), setjmp((buf)->jmpbuf))
#define nlr_pop() { nlr_setjmp_top = nlr_setjmp_top->prev; }
#define nlr_push(buf) ((buf)->prev = MP_STATE_VM(nlr_top), MP_STATE_VM(nlr_top) = (buf), setjmp((buf)->jmpbuf))
#define nlr_pop() { MP_STATE_VM(nlr_top) = MP_STATE_VM(nlr_top)->prev; }
#define nlr_jump(val) nlr_setjmp_jump(val)
#else
unsigned int nlr_push(nlr_buf_t *);
@@ -91,3 +96,5 @@ void nlr_jump_fail(void *val);
nlr_jump(_val); \
} while (0)
#endif
#endif // __MICROPY_INCLUDED_PY_NLR_H__

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