From 9956fd0710c3866b9df37857c9aa62b8bb681403 Mon Sep 17 00:00:00 2001
From: Paul Sokolovsky <pfalcon@users.sourceforge.net>
Date: Sat, 21 Oct 2017 11:06:32 +0300
Subject: [PATCH] py/objtype: Fit qstrs for special methods in byte type.

Update makeqstrdata.py to sort strings starting with "__" to the beginning
of qstr list, so they get low qstr id's, guaranteedly fitting in 8 bits.
Then use this property to further compact op_id => qstr mapping arrays.
---
 py/makeqstrdata.py | 10 +++++++++-
 py/objtype.c       | 10 +++++++---
 py/runtime.h       |  4 ++--
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 7249769f4..38fde1a9c 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -108,7 +108,15 @@ def parse_input_headers(infiles):
                     continue
 
                 # add the qstr to the list, with order number to retain original order in file
-                qstrs[ident] = (len(qstrs), ident, qstr)
+                order = len(qstrs)
+                # but put special method names like __add__ at the top of list, so
+                # that their id's fit into a byte
+                if ident == "":
+                    # Sort empty qstr above all still
+                    order = -200000
+                elif ident.startswith("__"):
+                    order -= 100000
+                qstrs[ident] = (order, ident, qstr)
 
     if not qcfgs:
         sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n")
diff --git a/py/objtype.c b/py/objtype.c
index 45b119f45..e75407683 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -332,7 +332,9 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
     return MP_OBJ_FROM_PTR(o);
 }
 
-const uint16_t mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
     [MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
     [MP_UNARY_OP_LEN] = MP_QSTR___len__,
     [MP_UNARY_OP_HASH] = MP_QSTR___hash__,
@@ -406,9 +408,11 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
 }
 
 // Binary-op enum values not listed here will have the default value of 0 in the
-// table, corresponding to MP_QSTR_, and are therefore unsupported (a lookup will
+// table, corresponding to MP_QSTR_NULL, and are therefore unsupported (a lookup will
 // fail).  They can be added at the expense of code size for the qstr.
-const uint16_t mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
     [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
     [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
     [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
diff --git a/py/runtime.h b/py/runtime.h
index d410b5614..9c1921cb5 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -57,8 +57,8 @@ typedef struct _mp_arg_t {
 } mp_arg_t;
 
 // Tables mapping operator enums to qstrs, defined in objtype.c
-extern const uint16_t mp_unary_op_method_name[];
-extern const uint16_t mp_binary_op_method_name[];
+extern const byte mp_unary_op_method_name[];
+extern const byte mp_binary_op_method_name[];
 
 void mp_init(void);
 void mp_deinit(void);
-- 
GitLab