1# test importing of .mpy files with native code (x64 only)
2
3try:
4    import usys, uio, uos
5
6    uio.IOBase
7    uos.mount
8except (ImportError, AttributeError):
9    print("SKIP")
10    raise SystemExit
11
12if not (usys.platform == "linux" and usys.maxsize > 2 ** 32):
13    print("SKIP")
14    raise SystemExit
15
16
17class UserFile(uio.IOBase):
18    def __init__(self, data):
19        self.data = memoryview(data)
20        self.pos = 0
21
22    def readinto(self, buf):
23        n = min(len(buf), len(self.data) - self.pos)
24        buf[:n] = self.data[self.pos : self.pos + n]
25        self.pos += n
26        return n
27
28    def ioctl(self, req, arg):
29        return 0
30
31
32class UserFS:
33    def __init__(self, files):
34        self.files = files
35
36    def mount(self, readonly, mksfs):
37        pass
38
39    def umount(self):
40        pass
41
42    def stat(self, path):
43        if path in self.files:
44            return (32768, 0, 0, 0, 0, 0, 0, 0, 0, 0)
45        raise OSError
46
47    def open(self, path, mode):
48        return UserFile(self.files[path])
49
50
51# these are the test .mpy files
52# fmt: off
53user_files = {
54    # bad architecture
55    '/mod0.mpy': b'M\x05\xff\x00\x10',
56
57    # test loading of viper and asm
58    '/mod1.mpy': (
59        b'M\x05\x0b\x1f\x20' # header
60
61        b'\x20' # n bytes, bytecode
62            b'\x00\x08\x02m\x02m' # prelude
63            b'\x51' # LOAD_CONST_NONE
64            b'\x63' # RETURN_VALUE
65
66            b'\x00\x02' # n_obj, n_raw_code
67
68        b'\x22' # n bytes, viper code
69            b'\x00\x00\x00\x00\x00\x00' # dummy machine code
70            b'\x00\x00' # qstr0
71            b'\x01\x0c\x0aprint' # n_qstr, qstr0
72            b'\x00\x00\x00' # scope_flags, n_obj, n_raw_code
73
74        b'\x23' # n bytes, asm code
75            b'\x00\x00\x00\x00\x00\x00\x00\x00' # dummy machine code
76            b'\x00\x00\x00' # scope_flags, n_pos_args, type_sig
77    ),
78
79    # test loading viper with additional scope flags and relocation
80    '/mod2.mpy': (
81        b'M\x05\x0b\x1f\x20' # header
82
83        b'\x20' # n bytes, bytecode
84            b'\x00\x08\x02m\x02m' # prelude
85            b'\x51' # LOAD_CONST_NONE
86            b'\x63' # RETURN_VALUE
87
88            b'\x00\x01' # n_obj, n_raw_code
89
90        b'\x12' # n bytes(=4), viper code
91            b'\x00\x00\x00\x00' # dummy machine code
92            b'\x00' # n_qstr
93            b'\x70' # scope_flags: VIPERBSS | VIPERRODATA | VIPERRELOC
94            b'\x00\x00' # n_obj, n_raw_code
95            b'\x06rodata' # rodata, 6 bytes
96            b'\x04' # bss, 4 bytes
97            b'\x03\x01\x00' # dummy relocation of rodata
98    ),
99}
100# fmt: on
101
102# create and mount a user filesystem
103uos.mount(UserFS(user_files), "/userfs")
104usys.path.append("/userfs")
105
106# import .mpy files from the user filesystem
107for i in range(len(user_files)):
108    mod = "mod%u" % i
109    try:
110        __import__(mod)
111        print(mod, "OK")
112    except ValueError as er:
113        print(mod, "ValueError", er)
114
115# unmount and undo path addition
116uos.umount("/userfs")
117usys.path.pop()
118