py: Improve native emitter; now supports more opcodes.
diff --git a/py/emitnative.c b/py/emitnative.c
index 4ef9e5a..acf2735 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -561,6 +561,17 @@
 #endif
 }
 
+// the first arg is stored in the code aligned on a machine_uint_t boundary
+STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val, int arg_reg) {
+    need_reg_all(emit);
+    ASM_MOV_ALIGNED_IMM_TO_REG(arg_val, arg_reg);
+#if N_X64
+    asm_x64_call_ind(emit->as, fun, REG_RAX);
+#elif N_THUMB
+    asm_thumb_bl_ind(emit->as, mp_fun_table[fun_kind], fun_kind, REG_R3);
+#endif
+}
+
 STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val1, int arg_reg1, machine_int_t arg_val2, int arg_reg2) {
     need_reg_all(emit);
     ASM_MOV_IMM_TO_REG(arg_val1, arg_reg1);
@@ -688,7 +699,7 @@
     DEBUG_printf("load_const_int %s\n", qstr_str(st));
     // for viper: load integer, check fits in 32 bits
     emit_native_pre(emit);
-    emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_long_str, qst, REG_ARG_1);
+    emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_qstr, qst, REG_ARG_1);
     emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
 }
 
@@ -945,6 +956,8 @@
 
 STATIC void emit_native_jump(emit_t *emit, uint label) {
     emit_native_pre(emit);
+    // need to commit stack because we are jumping elsewhere
+    need_stack_settled(emit);
 #if N_X64
     asm_x64_jmp_label(emit->as, label);
 #elif N_THUMB
@@ -953,33 +966,29 @@
     emit_post(emit);
 }
 
-STATIC void emit_native_pop_jump_pre_helper(emit_t *emit, uint label) {
+STATIC void emit_native_jump_helper(emit_t *emit, uint label, bool pop) {
     vtype_kind_t vtype = peek_vtype(emit);
     if (vtype == VTYPE_BOOL) {
         emit_pre_pop_reg(emit, &vtype, REG_RET);
+        if (!pop) {
+            adjust_stack(emit, 1);
+        }
     } else if (vtype == VTYPE_PYOBJ) {
         emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
         emit_call(emit, MP_F_OBJ_IS_TRUE, mp_obj_is_true);
+        if (!pop) {
+            emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
+        }
     } else {
         printf("ViperTypeError: expecting a bool or pyobj, got %d\n", vtype);
         assert(0);
     }
-}
-
-STATIC void emit_native_pop_jump_if_false(emit_t *emit, uint label) {
-    emit_native_pop_jump_pre_helper(emit, label);
-#if N_X64
-    asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
-    asm_x64_jcc_label(emit->as, JCC_JZ, label);
-#elif N_THUMB
-    asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
-    asm_thumb_bcc_label(emit->as, THUMB_CC_EQ, label);
-#endif
-    emit_post(emit);
+    // need to commit stack because we may jump elsewhere
+    need_stack_settled(emit);
 }
 
 STATIC void emit_native_pop_jump_if_true(emit_t *emit, uint label) {
-    emit_native_pop_jump_pre_helper(emit, label);
+    emit_native_jump_helper(emit, label, true);
 #if N_X64
     asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
     asm_x64_jcc_label(emit->as, JCC_JNZ, label);
@@ -990,19 +999,52 @@
     emit_post(emit);
 }
 
-STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, uint label) {
-    assert(0);
+STATIC void emit_native_pop_jump_if_false(emit_t *emit, uint label) {
+    emit_native_jump_helper(emit, label, true);
+#if N_X64
+    asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
+    asm_x64_jcc_label(emit->as, JCC_JZ, label);
+#elif N_THUMB
+    asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
+    asm_thumb_bcc_label(emit->as, THUMB_CC_EQ, label);
+#endif
+    emit_post(emit);
 }
+
+STATIC void emit_native_jump_if_true_or_pop(emit_t *emit, uint label) {
+    emit_native_jump_helper(emit, label, false);
+#if N_X64
+    asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
+    asm_x64_jcc_label(emit->as, JCC_JNZ, label);
+#elif N_THUMB
+    asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
+    asm_thumb_bcc_label(emit->as, THUMB_CC_NE, label);
+#endif
+    adjust_stack(emit, -1);
+    emit_post(emit);
+}
+
 STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) {
-    assert(0);
+    emit_native_jump_helper(emit, label, false);
+#if N_X64
+    asm_x64_test_r8_with_r8(emit->as, REG_RET, REG_RET);
+    asm_x64_jcc_label(emit->as, JCC_JZ, label);
+#elif N_THUMB
+    asm_thumb_cmp_rlo_i8(emit->as, REG_RET, 0);
+    asm_thumb_bcc_label(emit->as, THUMB_CC_EQ, label);
+#endif
+    adjust_stack(emit, -1);
+    emit_post(emit);
 }
 
 STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) {
     emit_native_jump(emit, label); // TODO properly
 }
+
 STATIC void emit_native_continue_loop(emit_t *emit, uint label, int except_depth) {
-    assert(0);
+    emit_native_jump(emit, label); // TODO properly
 }
+
 STATIC void emit_native_setup_with(emit_t *emit, uint label) {
     // not supported, or could be with runtime call
     assert(0);
@@ -1037,7 +1079,7 @@
     emit_access_stack(emit, 1, &vtype, REG_ARG_1);
     assert(vtype == VTYPE_PYOBJ);
     emit_call(emit, MP_F_ITERNEXT, mp_iternext);
-    ASM_MOV_IMM_TO_REG((machine_uint_t)MP_OBJ_NULL, REG_TEMP1);
+    ASM_MOV_IMM_TO_REG((machine_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1);
 #if N_X64
     asm_x64_cmp_r64_with_r64(emit->as, REG_RET, REG_TEMP1);
     asm_x64_jcc_label(emit->as, JCC_JE, label);
@@ -1203,14 +1245,27 @@
 }
 
 STATIC void emit_native_unpack_ex(emit_t *emit, int n_left, int n_right) {
-    assert(0);
+    // TODO this is untested
+    DEBUG_printf("unpack_ex %d %d\n", n_left, n_right);
+    vtype_kind_t vtype_base;
+    emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
+    assert(vtype_base == VTYPE_PYOBJ);
+    emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_left + n_right); // arg3 = dest ptr
+    emit_call_with_imm_arg(emit, MP_F_UNPACK_EX, mp_unpack_ex, n_left + n_right, REG_ARG_2); // arg2 = n_left + n_right
 }
 
 STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) {
     // call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
-    assert(n_pos_defaults == 0 && n_kw_defaults == 0);
     emit_native_pre(emit);
-    emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (machine_uint_t)scope->raw_code, REG_ARG_1, (machine_uint_t)MP_OBJ_NULL, REG_ARG_2, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3);
+    if (n_pos_defaults == 0 && n_kw_defaults == 0) {
+        emit_call_with_3_imm_args_and_first_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (machine_uint_t)scope->raw_code, REG_ARG_1, (machine_uint_t)MP_OBJ_NULL, REG_ARG_2, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3);
+    } else {
+        vtype_kind_t vtype_def_tuple, vtype_def_dict;
+        emit_pre_pop_reg_reg(emit, &vtype_def_dict, REG_ARG_3, &vtype_def_tuple, REG_ARG_2);
+        assert(vtype_def_tuple == VTYPE_PYOBJ);
+        assert(vtype_def_dict == VTYPE_PYOBJ);
+        emit_call_with_imm_arg_aligned(emit, MP_F_MAKE_FUNCTION_FROM_RAW_CODE, mp_make_function_from_raw_code, (machine_uint_t)scope->raw_code, REG_ARG_1);
+    }
     emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
 }
 
diff --git a/py/obj.h b/py/obj.h
index 70651f9..4797856 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -370,7 +370,7 @@
 mp_obj_t mp_obj_new_cell(mp_obj_t obj);
 mp_obj_t mp_obj_new_int(machine_int_t value);
 mp_obj_t mp_obj_new_int_from_uint(machine_uint_t value);
-mp_obj_t mp_obj_new_int_from_long_str(const char *s);
+mp_obj_t mp_obj_new_int_from_qstr(qstr qst);
 mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
 mp_obj_t mp_obj_new_str(const byte* data, uint len, bool make_qstr_if_not_already);
 mp_obj_t mp_obj_new_bytes(const byte* data, uint len);
diff --git a/py/objint.c b/py/objint.c
index dbc385c..c8bcb60 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -228,7 +228,7 @@
 }
 
 // This is called only with strings whose value doesn't fit in SMALL_INT
-mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
+mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
     nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build"));
     return mp_const_none;
 }
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index d00bb6d..f648615 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -161,7 +161,8 @@
     return o;
 }
 
-mp_obj_t mp_obj_new_int_from_long_str(const char *s) {
+mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
+    const char *s = qstr_str(qst);
     long long v;
     char *end;
     // TODO: this doesn't handle Python hacked 0o octal syntax
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index d44ff7a..a7fcac9 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -260,9 +260,10 @@
     return mp_obj_new_int_from_ll(value);
 }
 
-mp_obj_t mp_obj_new_int_from_long_str(const char *str) {
+mp_obj_t mp_obj_new_int_from_qstr(qstr qst) {
     mp_obj_int_t *o = mp_obj_int_new_mpz();
-    uint len = strlen(str);
+    uint len;
+    const char* str = (const char*)qstr_data(qst, &len);
     int base = 0;
     int skip = mp_parse_num_base(str, len, &base);
     str += skip;
diff --git a/py/runtime.c b/py/runtime.c
index fd5752f..a5a5bc5 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -1132,7 +1132,7 @@
 // these must correspond to the respective enum
 void *const mp_fun_table[MP_F_NUMBER_OF] = {
     mp_load_const_dec,
-    mp_obj_new_int_from_long_str,
+    mp_obj_new_int_from_qstr,
     mp_load_const_str,
     mp_load_name,
     mp_load_global,
@@ -1162,6 +1162,7 @@
     mp_import_all,
     mp_obj_new_slice,
     mp_unpack_sequence,
+    mp_unpack_ex,
 };
 
 /*
diff --git a/py/runtime0.h b/py/runtime0.h
index 9d59456..ccc33f3 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -121,6 +121,7 @@
     MP_F_IMPORT_ALL,
     MP_F_NEW_SLICE,
     MP_F_UNPACK_SEQUENCE,
+    MP_F_UNPACK_EX,
     MP_F_NUMBER_OF,
 } mp_fun_kind_t;
 
diff --git a/py/vm.c b/py/vm.c
index f2a48e2..5b4d0d1 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -314,7 +314,7 @@
 
                 ENTRY(MP_BC_LOAD_CONST_INT):
                     DECODE_QSTR;
-                    PUSH(mp_obj_new_int_from_long_str(qstr_str(qst)));
+                    PUSH(mp_obj_new_int_from_qstr(qst));
                     DISPATCH();
 
                 ENTRY(MP_BC_LOAD_CONST_DEC):