From 18e6358480e640fd94a9383d5fa7d9b8cc2b9f73 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Tue, 22 May 2018 22:33:26 +1000
Subject: [PATCH] py/emit: Combine setup with/except/finally into one emit
 function.

This patch reduces code size by:

   bare-arm:   -16
minimal x86:  -156
   unix x64:  -288
unix nanbox:  -184
      stm32:   -48
     cc3200:   -16
    esp8266:   -96
      esp32:   -16

The last 10 patches combined reduce code size by:

   bare-arm:  -164
minimal x86: -1260
   unix x64: -3416
unix nanbox: -1616
      stm32:  -676
     cc3200:  -232
    esp8266: -1144
      esp32:  -268
---
 py/compile.c    | 14 +++++++-------
 py/emit.h       | 13 +++++++------
 py/emitbc.c     | 29 ++++++++++++-----------------
 py/emitnative.c | 33 ++++++++++++++++-----------------
 4 files changed, 42 insertions(+), 47 deletions(-)

diff --git a/py/compile.c b/py/compile.c
index be1fd8b1f..c62ed057d 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1516,7 +1516,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
     uint l1 = comp_next_label(comp);
     uint success_label = comp_next_label(comp);
 
-    EMIT_ARG(setup_except, l1);
+    EMIT_ARG(setup_block, l1, MP_EMIT_SETUP_BLOCK_EXCEPT);
     compile_increase_except_level(comp);
 
     compile_node(comp, pn_body); // body
@@ -1571,7 +1571,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
         uint l3 = 0;
         if (qstr_exception_local != 0) {
             l3 = comp_next_label(comp);
-            EMIT_ARG(setup_finally, l3);
+            EMIT_ARG(setup_block, l3, MP_EMIT_SETUP_BLOCK_FINALLY);
             compile_increase_except_level(comp);
         }
         compile_node(comp, pns_except->nodes[1]);
@@ -1606,7 +1606,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
 STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
     uint l_finally_block = comp_next_label(comp);
 
-    EMIT_ARG(setup_finally, l_finally_block);
+    EMIT_ARG(setup_block, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY);
     compile_increase_except_level(comp);
 
     if (n_except == 0) {
@@ -1668,12 +1668,12 @@ STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *n
             // this pre-bit is of the form "a as b"
             mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0];
             compile_node(comp, pns->nodes[0]);
-            EMIT_ARG(setup_with, l_end);
+            EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH);
             c_assign(comp, pns->nodes[1], ASSIGN_STORE);
         } else {
             // this pre-bit is just an expression
             compile_node(comp, nodes[0]);
-            EMIT_ARG(setup_with, l_end);
+            EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH);
             EMIT(pop_top);
         }
         compile_increase_except_level(comp);
@@ -1726,7 +1726,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns
 
     EMIT_ARG(label_assign, continue_label);
 
-    EMIT_ARG(setup_except, try_exception_label);
+    EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT);
     compile_increase_except_level(comp);
 
     compile_load_id(comp, context);
@@ -1797,7 +1797,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
         compile_load_id(comp, context);
         EMIT_ARG(load_method, MP_QSTR___aexit__, false);
 
-        EMIT_ARG(setup_except, try_exception_label);
+        EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT);
         compile_increase_except_level(comp);
         // compile additional pre-bits and the body
         compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body);
diff --git a/py/emit.h b/py/emit.h
index 7f0d8c0f7..aa98efa77 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -78,6 +78,11 @@ typedef enum {
 #define MP_EMIT_ATTR_STORE (1)
 #define MP_EMIT_ATTR_DELETE (2)
 
+// Kind for emit->setup_block()
+#define MP_EMIT_SETUP_BLOCK_WITH (0)
+#define MP_EMIT_SETUP_BLOCK_EXCEPT (2)
+#define MP_EMIT_SETUP_BLOCK_FINALLY (3)
+
 // Kind for emit->build()
 #define MP_EMIT_BUILD_TUPLE (0)
 #define MP_EMIT_BUILD_LIST (1)
@@ -128,10 +133,8 @@ typedef struct _emit_method_table_t {
     void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label);
     void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label);
     void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
-    void (*setup_with)(emit_t *emit, mp_uint_t label);
+    void (*setup_block)(emit_t *emit, mp_uint_t label, int kind);
     void (*with_cleanup)(emit_t *emit, mp_uint_t label);
-    void (*setup_except)(emit_t *emit, mp_uint_t label);
-    void (*setup_finally)(emit_t *emit, mp_uint_t label);
     void (*end_finally)(emit_t *emit);
     void (*get_iter)(emit_t *emit, bool use_stack);
     void (*for_iter)(emit_t *emit, mp_uint_t label);
@@ -223,10 +226,8 @@ void mp_emit_bc_jump(emit_t *emit, mp_uint_t label);
 void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label);
 void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label);
 void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
-void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label);
+void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind);
 void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label);
-void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label);
-void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label);
 void mp_emit_bc_end_finally(emit_t *emit);
 void mp_emit_bc_get_iter(emit_t *emit, bool use_stack);
 void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label);
diff --git a/py/emitbc.c b/py/emitbc.c
index 4c587c72e..f3951e9cb 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -719,11 +719,18 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept
     }
 }
 
-void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) {
+void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) {
+    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH);
+    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT);
+    MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY);
+    if (kind == MP_EMIT_SETUP_BLOCK_WITH) {
     // The SETUP_WITH opcode pops ctx_mgr from the top of the stack
     // and then pushes 3 entries: __exit__, ctx_mgr, as_value.
-    emit_bc_pre(emit, 2);
-    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
+        emit_bc_pre(emit, 2);
+    } else {
+        emit_bc_pre(emit, 0);
+    }
+    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label);
 }
 
 void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
@@ -732,17 +739,7 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
     mp_emit_bc_label_assign(emit, label);
     emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method
     emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
-    emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with
-}
-
-void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) {
-    emit_bc_pre(emit, 0);
-    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
-}
-
-void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) {
-    emit_bc_pre(emit, 0);
-    emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
+    emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH)
 }
 
 void mp_emit_bc_end_finally(emit_t *emit) {
@@ -953,10 +950,8 @@ const emit_method_table_t emit_bc_method_table = {
     mp_emit_bc_pop_jump_if,
     mp_emit_bc_jump_if_or_pop,
     mp_emit_bc_unwind_jump,
-    mp_emit_bc_setup_with,
+    mp_emit_bc_setup_block,
     mp_emit_bc_with_cleanup,
-    mp_emit_bc_setup_except,
-    mp_emit_bc_setup_finally,
     mp_emit_bc_end_finally,
     mp_emit_bc_get_iter,
     mp_emit_bc_for_iter,
diff --git a/py/emitnative.c b/py/emitnative.c
index 331e4cf18..ad8f04aac 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -1617,6 +1617,21 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
     // stack: (..., __exit__, self, as_value, nlr_buf, as_value)
 }
 
+STATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) {
+    if (kind == MP_EMIT_SETUP_BLOCK_WITH) {
+        emit_native_setup_with(emit, label);
+    } else {
+        // Set up except and finally
+        emit_native_pre(emit);
+        // need to commit stack because we may jump elsewhere
+        need_stack_settled(emit);
+        emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
+        emit_call(emit, MP_F_NLR_PUSH);
+        ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
+        emit_post(emit);
+    }
+}
+
 STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
     // note: label+1 is available as an auxiliary label
 
@@ -1686,20 +1701,6 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
     emit_native_label_assign(emit, label + 1);
 }
 
-STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) {
-    emit_native_pre(emit);
-    // need to commit stack because we may jump elsewhere
-    need_stack_settled(emit);
-    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
-    emit_call(emit, MP_F_NLR_PUSH);
-    ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
-    emit_post(emit);
-}
-
-STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) {
-    emit_native_setup_except(emit, label);
-}
-
 STATIC void emit_native_end_finally(emit_t *emit) {
     // logic:
     //   exc = pop_stack
@@ -2254,10 +2255,8 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
     emit_native_pop_jump_if,
     emit_native_jump_if_or_pop,
     emit_native_unwind_jump,
-    emit_native_setup_with,
+    emit_native_setup_block,
     emit_native_with_cleanup,
-    emit_native_setup_except,
-    emit_native_setup_finally,
     emit_native_end_finally,
     emit_native_get_iter,
     emit_native_for_iter,
-- 
GitLab