Skip to content
Snippets Groups Projects
Commit 95836f84 authored by Damien George's avatar Damien George
Browse files

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.
parent 6942f80a
No related branches found
No related tags found
No related merge requests found
......@@ -73,16 +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\\x00\\x00" "")')
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)
qdata = qstr.replace('"', '\\"')
print('QDEF(MP_QSTR_%s, (const byte*)"\\x%02x\\x%02x\\x%02x\\x%02x" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen & 0xff, (qlen >> 8) & 0xff, qdata))
if qlen >= cfg_max_len:
print('qstr is too long:', qstr)
assert False
qlen_str = ('\\x%02x' * cfg_bytes_len) % tuple(qlen.to_bytes(cfg_bytes_len, 'little'))
print('QDEF(MP_QSTR_%s, (const byte*)"\\x%02x\\x%02x%s" "%s")' % (ident, qhash & 0xff, (qhash >> 8) & 0xff, qlen_str, qdata))
return True
......
......@@ -112,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 */
......
......@@ -50,9 +50,17 @@
// - \0 terminated (for now, so they can be printed using printf)
#define Q_GET_HASH(q) ((q)[0] | ((q)[1] << 8))
#define Q_GET_ALLOC(q) (4 + Q_GET_LENGTH(q) + 1)
#define Q_GET_LENGTH(q) ((q)[2] | ((q)[3] << 8))
#define Q_GET_DATA(q) ((q) + 4)
#define Q_GET_ALLOC(q) (2 + MICROPY_QSTR_BYTES_IN_LEN + Q_GET_LENGTH(q) + 1)
#define Q_GET_DATA(q) ((q) + 2 + MICROPY_QSTR_BYTES_IN_LEN)
#if MICROPY_QSTR_BYTES_IN_LEN == 1
#define Q_GET_LENGTH(q) ((q)[2])
#define Q_SET_LENGTH(q, len) do { (q)[2] = (len); } while (0)
#elif MICROPY_QSTR_BYTES_IN_LEN == 2
#define Q_GET_LENGTH(q) ((q)[2] | ((q)[3] << 8))
#define Q_SET_LENGTH(q, len) do { (q)[2] = (len); (q)[3] = (len) >> 8; } while (0)
#else
#error unimplemented qstr length decoding
#endif
// this must match the equivalent function in makeqstrdata.py
mp_uint_t qstr_compute_hash(const byte *data, mp_uint_t len) {
......@@ -143,23 +151,21 @@ qstr qstr_from_strn(const char *str, mp_uint_t len) {
qstr q = qstr_find_strn(str, len);
if (q == 0) {
mp_uint_t hash = qstr_compute_hash((const byte*)str, len);
byte *q_ptr = m_new(byte, 4 + len + 1);
byte *q_ptr = m_new(byte, 2 + MICROPY_QSTR_BYTES_IN_LEN + len + 1);
q_ptr[0] = hash;
q_ptr[1] = hash >> 8;
q_ptr[2] = len;
q_ptr[3] = len >> 8;
memcpy(q_ptr + 4, str, len);
q_ptr[4 + len] = '\0';
Q_SET_LENGTH(q_ptr, len);
memcpy(q_ptr + 2 + MICROPY_QSTR_BYTES_IN_LEN, str, len);
q_ptr[2 + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0';
q = qstr_add(q_ptr);
}
return q;
}
byte *qstr_build_start(mp_uint_t len, byte **q_ptr) {
assert(len <= 65535);
*q_ptr = m_new(byte, 4 + len + 1);
(*q_ptr)[2] = len;
(*q_ptr)[3] = len >> 8;
assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN)));
*q_ptr = m_new(byte, 2 + MICROPY_QSTR_BYTES_IN_LEN + len + 1);
Q_SET_LENGTH(*q_ptr, len);
return Q_GET_DATA(*q_ptr);
}
......@@ -170,7 +176,7 @@ qstr qstr_build_end(byte *q_ptr) {
mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
q_ptr[0] = hash;
q_ptr[1] = hash >> 8;
q_ptr[4 + len] = '\0';
q_ptr[2 + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0';
q = qstr_add(q_ptr);
} else {
m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr));
......
......@@ -30,7 +30,7 @@
// That is, they are in ROM and you can reference them simply as MP_QSTR_xxxx.
// qstr configuration passed to makeqstrdata.py of the form QCFG(key, value)
//QCFG(somekey, somevalue)
QCFG(BYTES_IN_LEN, MICROPY_QSTR_BYTES_IN_LEN)
Q()
Q(*)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment