diff --git a/py/compile.c b/py/compile.c
index e1b62a11bf8a7f85d1e66614c7bd45a39ffd2823..ebd2abb5c49782ca93effe386cee7b19ebe28163 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1912,7 +1912,21 @@ void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
 
 void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
     compile_node(comp, pns->nodes[0]);
+#if MICROPY_EMIT_CPYTHON
     EMIT_ARG(unary_op, RT_UNARY_OP_NOT);
+#else
+    // eliminate use of NOT byte code
+    int l_load_false = comp_next_label(comp);
+    int l_done = comp_next_label(comp);
+    int stack_size = EMIT(get_stack_size);
+    EMIT_ARG(pop_jump_if_true, l_load_false);
+    EMIT_ARG(load_const_tok, MP_TOKEN_KW_TRUE);
+    EMIT_ARG(jump, l_done);
+    EMIT_ARG(label_assign, l_load_false);
+    EMIT_ARG(load_const_tok, MP_TOKEN_KW_FALSE);
+    EMIT_ARG(label_assign, l_done);
+    EMIT_ARG(set_stack_size, stack_size); // force stack size since it counts 1 pop and 2 pushes statically, but really it's 1 pop and 1 push dynamically
+#endif
 }
 
 void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) {
diff --git a/py/runtime.c b/py/runtime.c
index 27c0da3b896a5d7b884f745eaf73bb0da472eee5..39f297fce01c2e00bf19230c651f3e11beeb49bd 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -315,23 +315,18 @@ int rt_is_true(mp_obj_t arg) {
         return 0;
     } else if (arg == mp_const_true) {
         return 1;
-    } else if (MP_OBJ_IS_STR(arg)) {
-        return mp_obj_str_get_len(arg) != 0;
-    } else if (MP_OBJ_IS_TYPE(arg, &list_type)) {
-        uint len;
-        mp_obj_t *dummy;
-        mp_obj_list_get(arg, &len, &dummy);
-        return len != 0;
-    } else if (MP_OBJ_IS_TYPE(arg, &tuple_type)) {
-        uint len;
-        mp_obj_t *dummy;
-        mp_obj_tuple_get(arg, &len, &dummy);
-        return len != 0;
-    } else if (MP_OBJ_IS_TYPE(arg, &dict_type)) {
-        return mp_obj_dict_len(arg) != 0;
     } else {
-        assert(0);
-        return 0;
+        mp_obj_t len = mp_obj_len_maybe(arg);
+        if (len != MP_OBJ_NULL) {
+            // obj has a length, truth determined if len != 0
+            return len != MP_OBJ_NEW_SMALL_INT(0);
+        } else {
+            // TODO check for __bool__ method
+            // TODO check floats and complex numbers
+
+            // any other obj is true (TODO is that correct?)
+            return 1;
+        }
     }
 }
 
diff --git a/py/runtime0.h b/py/runtime0.h
index 4fdcdc3cc9fe2e84f8dc30d431f7dc57734846e0..b7b5afaeb679d5aabfa1c867c30029ea403137b4 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -1,5 +1,5 @@
 typedef enum {
-    RT_UNARY_OP_NOT,
+    RT_UNARY_OP_NOT, // TODO remove this op since it's no longer needed
     RT_UNARY_OP_POSITIVE,
     RT_UNARY_OP_NEGATIVE,
     RT_UNARY_OP_INVERT,