summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-02-19 23:56:23 +0000
committerDamien George <damien.p.george@gmail.com>2014-02-19 23:56:23 +0000
commitb74501c98f9abf84f659a447077989eb3ffeb46c (patch)
treea6e536dab080a1d4714187c52912890a5e62cfb3 /py
parent2e87c62cf62dfeb5b11022359511c31bbb35af54 (diff)
parent047cd40313e39b662650bbf6c8059ab0910e5986 (diff)
downloadmicropython-b74501c98f9abf84f659a447077989eb3ffeb46c.tar.gz
micropython-b74501c98f9abf84f659a447077989eb3ffeb46c.zip
Merge pull request #312 from pfalcon/int-varlen
Support varlen encoding for arbitrary int and uint numbers
Diffstat (limited to 'py')
-rw-r--r--py/emitbc.c62
-rw-r--r--py/showbc.c17
-rw-r--r--py/vm.c29
3 files changed, 74 insertions, 34 deletions
diff --git a/py/emitbc.c b/py/emitbc.c
index 269fcdeb7e..9fab977909 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -108,30 +108,46 @@ STATIC void emit_write_byte_code_byte_byte(emit_t* emit, byte b1, uint b2) {
}
STATIC void emit_write_byte_code_uint(emit_t* emit, uint num) {
- if (num <= 127) { // fits in 0x7f
- // fit argument in single byte
- byte* c = emit_get_cur_to_write_byte_code(emit, 1);
- c[0] = num;
- } else if (num <= 16383) { // fits in 0x3fff
- // fit argument in two bytes
- byte* c = emit_get_cur_to_write_byte_code(emit, 2);
- c[0] = (num >> 8) | 0x80;
- c[1] = num;
- } else {
- // larger numbers not implemented/supported
- assert(0);
- }
-}
-
-// integers (for small ints) are stored as 24 bits, in excess
+ // We store each 7 bits in a separate byte, and that's how many bytes needed
+ byte buf[(BYTES_PER_WORD * 8 + 7) / 7];
+ byte *p = buf + sizeof(buf);
+ // We encode in little-ending order, but store in big-endian, to help decoding
+ do {
+ *--p = num & 0x7f;
+ num >>= 7;
+ } while (num != 0);
+ byte* c = emit_get_cur_to_write_byte_code(emit, buf + sizeof(buf) - p);
+ while (p != buf + sizeof(buf) - 1) {
+ *c++ = *p++ | 0x80;
+ }
+ *c = *p;
+}
+
+// Similar to emit_write_byte_code_uint(), just some extra handling to encode sign
STATIC void emit_write_byte_code_byte_int(emit_t* emit, byte b1, machine_int_t num) {
- num += 0x800000;
- assert(0 <= num && num <= 0xffffff);
- byte* c = emit_get_cur_to_write_byte_code(emit, 4);
- c[0] = b1;
- c[1] = num;
- c[2] = num >> 8;
- c[3] = num >> 16;
+ emit_write_byte_code_byte(emit, b1);
+
+ // We store each 7 bits in a separate byte, and that's how many bytes needed
+ byte buf[(BYTES_PER_WORD * 8 + 7) / 7];
+ byte *p = buf + sizeof(buf);
+ // We encode in little-ending order, but store in big-endian, to help decoding
+ do {
+ *--p = num & 0x7f;
+ num >>= 7;
+ } while (num != 0 && num != -1);
+ // Make sure that highest bit we stored (mask 0x40) matches sign
+ // of the number. If not, store extra byte just to encode sign
+ if (num == -1 && (*p & 0x40) == 0) {
+ *--p = 0x7f;
+ } else if (num == 0 && (*p & 0x40) != 0) {
+ *--p = 0;
+ }
+
+ byte* c = emit_get_cur_to_write_byte_code(emit, buf + sizeof(buf) - p);
+ while (p != buf + sizeof(buf) - 1) {
+ *c++ = *p++ | 0x80;
+ }
+ *c = *p;
}
STATIC void emit_write_byte_code_byte_uint(emit_t* emit, byte b, uint num) {
diff --git a/py/showbc.c b/py/showbc.c
index e3387dbe27..837ee7611f 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -57,11 +57,18 @@ void mp_byte_code_print(const byte *ip, int len) {
printf("LOAD_CONST_ELLIPSIS");
break;
- case MP_BC_LOAD_CONST_SMALL_INT:
- unum = (ip[0] | (ip[1] << 8) | (ip[2] << 16)) - 0x800000;
- ip += 3;
- printf("LOAD_CONST_SMALL_INT %d", (int)unum);
- break;
+ case MP_BC_LOAD_CONST_SMALL_INT: {
+ int num = 0;
+ if ((ip[0] & 0x40) != 0) {
+ // Number is negative
+ num--;
+ }
+ do {
+ num = (num << 7) | (*ip & 0x7f);
+ } while ((*ip++ & 0x80) != 0);
+ printf("LOAD_CONST_SMALL_INT %d", num);
+ break;
+ }
case MP_BC_LOAD_CONST_INT:
DECODE_QSTR;
diff --git a/py/vm.c b/py/vm.c
index 573167b57d..cab340ff38 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -38,10 +38,20 @@ typedef enum {
UNWIND_JUMP,
} mp_unwind_reason_t;
-#define DECODE_UINT do { unum = *ip++; if (unum > 127) { unum = ((unum & 0x3f) << 8) | (*ip++); } } while (0)
+#define DECODE_UINT { \
+ unum = 0; \
+ do { \
+ unum = (unum << 7) + (*ip & 0x7f); \
+ } while ((*ip++ & 0x80) != 0); \
+}
#define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
#define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
-#define DECODE_QSTR do { qst = *ip++; if (qst > 127) { qst = ((qst & 0x3f) << 8) | (*ip++); } } while (0)
+#define DECODE_QSTR { \
+ qst = 0; \
+ do { \
+ qst = (qst << 7) + (*ip & 0x7f); \
+ } while ((*ip++ & 0x80) != 0); \
+}
#define PUSH(val) *++sp = (val)
#define POP() (*sp--)
#define TOP() (*sp)
@@ -146,11 +156,18 @@ dispatch_loop:
PUSH(mp_const_ellipsis);
break;
- case MP_BC_LOAD_CONST_SMALL_INT:
- unum = (ip[0] | (ip[1] << 8) | (ip[2] << 16)) - 0x800000;
- ip += 3;
- PUSH(MP_OBJ_NEW_SMALL_INT(unum));
+ case MP_BC_LOAD_CONST_SMALL_INT: {
+ int num = 0;
+ if ((ip[0] & 0x40) != 0) {
+ // Number is negative
+ num--;
+ }
+ do {
+ num = (num << 7) | (*ip & 0x7f);
+ } while ((*ip++ & 0x80) != 0);
+ PUSH(MP_OBJ_NEW_SMALL_INT(num));
break;
+ }
case MP_BC_LOAD_CONST_INT:
DECODE_QSTR;