circuitpython/tests/import/mpy_native.py
Damien George c8c0fd4ca3 py: Rework and compress second part of bytecode prelude.
This patch compresses the second part of the bytecode prelude which
contains the source file name, function name, source-line-number mapping
and cell closure information.  This part of the prelude now begins with a
single varible length unsigned integer which encodes 2 numbers, being the
byte-size of the following 2 sections in the header: the "source info
section" and the "closure section".  After decoding this variable unsigned
integer it's possible to skip over one or both of these sections very
easily.

This scheme saves about 2 bytes for most functions compared to the original
format: one in the case that there are no closure cells, and one because
padding was eliminated.
2019-10-01 12:26:22 +10:00

94 lines
2.3 KiB
Python

# test importing of .mpy files with native code (x64 only)
import sys, uio
try:
uio.IOBase
import uos
uos.mount
except (ImportError, AttributeError):
print("SKIP")
raise SystemExit
if not (sys.platform == 'linux' and sys.maxsize > 2 ** 32):
print("SKIP")
raise SystemExit
class UserFile(uio.IOBase):
def __init__(self, data):
self.data = data
self.pos = 0
def read(self):
return self.data
def readinto(self, buf):
n = 0
while n < len(buf) and self.pos < len(self.data):
buf[n] = self.data[self.pos]
n += 1
self.pos += 1
return n
def ioctl(self, req, arg):
return 0
class UserFS:
def __init__(self, files):
self.files = files
def mount(self, readonly, mksfs):
pass
def umount(self):
pass
def stat(self, path):
if path in self.files:
return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
raise OSError
def open(self, path, mode):
return UserFile(self.files[path])
# these are the test .mpy files
user_files = {
# bad architecture
'/mod0.mpy': b'M\x05\xff\x00\x10',
# test loading of viper and asm
'/mod1.mpy': (
b'M\x05\x0b\x1f\x20' # header
b'\x20' # n bytes, bytecode
b'\x00\x08\x00\x00\x00\x00' # prelude
b'\x51' # LOAD_CONST_NONE
b'\x63' # RETURN_VALUE
b'\x02m\x02m\x00\x02' # simple_name, source_file, n_obj, n_raw_code
b'\x22' # n bytes, viper code
b'\x00\x00\x00\x00\x00\x00' # dummy machine code
b'\x00\x00' # qstr0
b'\x01\x0c\x0aprint' # n_qstr, qstr0
b'\x00\x00\x00' # scope_flags, n_obj, n_raw_code
b'\x23' # n bytes, asm code
b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
),
}
# create and mount a user filesystem
uos.mount(UserFS(user_files), '/userfs')
sys.path.append('/userfs')
# import .mpy files from the user filesystem
for i in range(len(user_files)):
mod = 'mod%u' % i
try:
__import__(mod)
print(mod, 'OK')
except ValueError as er:
print(mod, 'ValueError', er)
# unmount and undo path addition
uos.umount('/userfs')
sys.path.pop()