diff --git a/bare-arm/main.c b/bare-arm/main.c
index c5a7fe060fb3b264f8e9ecae3ecc2288fe7dbb35..7405ece5e87f8c52628d5c10b497a20efafc2a01 100644
--- a/bare-arm/main.c
+++ b/bare-arm/main.c
@@ -45,7 +45,7 @@ mp_import_stat_t mp_import_stat(const char *path) {
     return MP_IMPORT_STAT_NO_EXIST;
 }
 
-mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index 9d1e90f5785442fda3adc335ece5cbf924617235..ccb813e3ed5ab048a8e9886579589b99e31d39d0 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -552,11 +552,19 @@ STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
 }
 MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
 
+STATIC mp_obj_t mp_builtin_globals(void) {
+    return MP_OBJ_FROM_PTR(mp_globals_get());
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_builtin_globals);
+
+STATIC mp_obj_t mp_builtin_locals(void) {
+    return MP_OBJ_FROM_PTR(mp_locals_get());
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_builtin_locals);
+
 // These are defined in terms of MicroPython API functions right away
 MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_id_obj, mp_obj_id);
 MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_len_obj, mp_obj_len);
-MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_globals_obj, mp_globals_get);
-MP_DEFINE_CONST_FUN_OBJ_0(mp_builtin_locals_obj, mp_locals_get);
 
 STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = {
     // built-in core functions
diff --git a/py/obj.h b/py/obj.h
index 3d9c00c52fea47a917364edaa44195f646c1dbf8..509d6a67b526a99549d3a03b65eaf0e8ed80dde3 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -270,14 +270,27 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o)
 
 #define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name
 
-#define MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, is_kw, n_args_min, n_args_max, fun_name) const mp_obj_fun_builtin_t obj_name = {{&mp_type_fun_builtin}, is_kw, n_args_min, n_args_max, (void(*)(void))fun_name}
-#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 0, 0, (mp_fun_0_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 1, 1, (mp_fun_1_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 2, 2, (mp_fun_2_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, 3, 3, (mp_fun_3_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, (mp_fun_var_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name)
-#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, (mp_fun_kw_t)fun_name)
+#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, 0, 0, .fun._0 = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, 1, 1, .fun._1 = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, 2, 2, .fun._2 = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, 3, 3, .fun._3 = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, false, n_args_min, n_args_max, .fun.var = fun_name}
+#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \
+    const mp_obj_fun_builtin_t obj_name = \
+        {{&mp_type_fun_builtin}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name}
 
 // These macros are used to define constant map/dict objects
 // You can put "static" in front of the definition to make it local
@@ -744,7 +757,14 @@ typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go
     bool is_kw : 1;
     mp_uint_t n_args_min : 15; // inclusive
     mp_uint_t n_args_max : 16; // inclusive
-    void (*fun)(void); // must be a pointer to a callable function in ROM
+    union {
+        mp_fun_0_t _0;
+        mp_fun_1_t _1;
+        mp_fun_2_t _2;
+        mp_fun_3_t _3;
+        mp_fun_var_t var;
+        mp_fun_kw_t kw;
+    } fun;
 } mp_obj_fun_builtin_t;
 
 qstr mp_obj_fun_get_name(mp_const_obj_t fun);
diff --git a/py/objfun.c b/py/objfun.c
index 34938ccfdd6e8efd8778e52feb2752a65e5923aa..a574926ba585f4ff1335069f464e0c8956cfdce8 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -66,7 +66,7 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n
         mp_map_t kw_args;
         mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
 
-        return ((mp_fun_kw_t)self->fun)(n_args, args, &kw_args);
+        return self->fun.kw(n_args, args, &kw_args);
 
     } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) {
         // function requires a fixed number of arguments
@@ -74,23 +74,23 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n
         // dispatch function call
         switch (self->n_args_min) {
             case 0:
-                return ((mp_fun_0_t)self->fun)();
+                return self->fun._0();
 
             case 1:
-                return ((mp_fun_1_t)self->fun)(args[0]);
+                return self->fun._1(args[0]);
 
             case 2:
-                return ((mp_fun_2_t)self->fun)(args[0], args[1]);
+                return self->fun._2(args[0], args[1]);
 
             case 3:
             default:
-                return ((mp_fun_3_t)self->fun)(args[0], args[1], args[2]);
+                return self->fun._3(args[0], args[1], args[2]);
         }
 
     } else {
         // function takes a variable number of arguments, but no keywords
 
-        return ((mp_fun_var_t)self->fun)(n_args, args);
+        return self->fun.var(n_args, args);
     }
 }
 
diff --git a/qemu-arm/main.c b/qemu-arm/main.c
index 66c404254e1f96ada3849106a553b664ca7672e0..e0f9a10ae62d0c46458db935182f3dc8280ca36c 100644
--- a/qemu-arm/main.c
+++ b/qemu-arm/main.c
@@ -52,7 +52,7 @@ mp_import_stat_t mp_import_stat(const char *path) {
     return MP_IMPORT_STAT_NO_EXIST;
 }
 
-mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c
index 43b06d06df24dcb6849c679b563479e83d4dbf68..f678946d49748e8a55a977d3be75e88297dfa6ca 100644
--- a/qemu-arm/test_main.c
+++ b/qemu-arm/test_main.c
@@ -82,7 +82,7 @@ mp_import_stat_t mp_import_stat(const char *path) {
     return MP_IMPORT_STAT_NO_EXIST;
 }
 
-mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
     return mp_const_none;
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
diff --git a/unix/input.c b/unix/input.c
index b2cf8efa8af489947b914dd842bbac30c0555801..66b3314c98e3d638b1dcd87c99a4490b7691eb7c 100644
--- a/unix/input.c
+++ b/unix/input.c
@@ -158,7 +158,7 @@ void prompt_write_history(void) {
 #endif
 }
 
-STATIC mp_obj_t mp_builtin_input(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t mp_builtin_input(mp_uint_t n_args, const mp_obj_t *args) {
     if (n_args == 1) {
         mp_obj_print(args[0], PRINT_STR);
     }
@@ -171,5 +171,4 @@ STATIC mp_obj_t mp_builtin_input(uint n_args, const mp_obj_t *args) {
     free(line);
     return o;
 }
-
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj, 0, 1, mp_builtin_input);
diff --git a/unix/moduselect.c b/unix/moduselect.c
index 537bd47960ebe9c71e196156554d935bf193a81f..7e0ec049f1ff629b0686dc148179515d7246dccc 100644
--- a/unix/moduselect.c
+++ b/unix/moduselect.c
@@ -52,7 +52,7 @@ typedef struct _mp_obj_poll_t {
 } mp_obj_poll_t;
 
 /// \method register(obj[, eventmask])
-STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t poll_register(mp_uint_t n_args, const mp_obj_t *args) {
     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     int fd = mp_obj_get_int(args[1]);
     mp_uint_t flags;
@@ -129,7 +129,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
 
 /// \method poll([timeout])
 /// Timeout is in milliseconds.
-STATIC mp_obj_t poll_poll(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t poll_poll(mp_uint_t n_args, const mp_obj_t *args) {
     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
 
     // work out timeout (it's given already in ms)