Commit dd11af20 authored by Damien George's avatar Damien George
Browse files

py: Add LOAD_SUPER_METHOD bytecode to allow heap-free super meth calls.

This patch allows the following code to run without allocating on the heap:

    super().foo(...)

Before this patch such a call would allocate a super object on the heap and
then load the foo method and call it right away.  The super object is only
needed to perform the lookup of the method and not needed after that.  This
patch makes an optimisation to allocate the super object on the C stack and
discard it right after use.

Changes in code size due to this patch are:

   bare-arm: +128
    minimal: +232
   unix x64: +416
unix nanbox: +364
     stmhal: +184
    esp8266: +340
     cc3200: +128
parent 5335942b
No preview for this file type
...@@ -304,7 +304,7 @@ STATIC const byte opcode_format_table[64] = { ...@@ -304,7 +304,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(U, U, U, U), // 0x0c-0x0f OC4(U, U, U, U), // 0x0c-0x0f
OC4(B, B, B, U), // 0x10-0x13 OC4(B, B, B, U), // 0x10-0x13
OC4(V, U, Q, V), // 0x14-0x17 OC4(V, U, Q, V), // 0x14-0x17
OC4(B, U, V, V), // 0x18-0x1b OC4(B, V, V, Q), // 0x18-0x1b
OC4(Q, Q, Q, Q), // 0x1c-0x1f OC4(Q, Q, Q, Q), // 0x1c-0x1f
OC4(B, B, V, V), // 0x20-0x23 OC4(B, B, V, V), // 0x20-0x23
OC4(Q, Q, Q, B), // 0x24-0x27 OC4(Q, Q, Q, B), // 0x24-0x27
......
...@@ -37,12 +37,13 @@ ...@@ -37,12 +37,13 @@
#define MP_BC_LOAD_CONST_OBJ (0x17) // ptr #define MP_BC_LOAD_CONST_OBJ (0x17) // ptr
#define MP_BC_LOAD_NULL (0x18) #define MP_BC_LOAD_NULL (0x18)
#define MP_BC_LOAD_FAST_N (0x1a) // uint #define MP_BC_LOAD_FAST_N (0x19) // uint
#define MP_BC_LOAD_DEREF (0x1b) // uint #define MP_BC_LOAD_DEREF (0x1a) // uint
#define MP_BC_LOAD_NAME (0x1c) // qstr #define MP_BC_LOAD_NAME (0x1b) // qstr
#define MP_BC_LOAD_GLOBAL (0x1d) // qstr #define MP_BC_LOAD_GLOBAL (0x1c) // qstr
#define MP_BC_LOAD_ATTR (0x1e) // qstr #define MP_BC_LOAD_ATTR (0x1d) // qstr
#define MP_BC_LOAD_METHOD (0x1f) // qstr #define MP_BC_LOAD_METHOD (0x1e) // qstr
#define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr
#define MP_BC_LOAD_BUILD_CLASS (0x20) #define MP_BC_LOAD_BUILD_CLASS (0x20)
#define MP_BC_LOAD_SUBSCR (0x21) #define MP_BC_LOAD_SUBSCR (0x21)
......
...@@ -1694,7 +1694,7 @@ STATIC void compile_yield_from(compiler_t *comp) { ...@@ -1694,7 +1694,7 @@ STATIC void compile_yield_from(compiler_t *comp) {
#if MICROPY_PY_ASYNC_AWAIT #if MICROPY_PY_ASYNC_AWAIT
STATIC void compile_await_object_method(compiler_t *comp, qstr method) { STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
EMIT_ARG(load_method, method); EMIT_ARG(load_method, method, false);
EMIT_ARG(call_method, 0, 0, 0); EMIT_ARG(call_method, 0, 0, 0);
compile_yield_from(comp); compile_yield_from(comp);
} }
...@@ -1785,7 +1785,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod ...@@ -1785,7 +1785,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
} }
compile_load_id(comp, context); compile_load_id(comp, context);
EMIT_ARG(load_method, MP_QSTR___aexit__); EMIT_ARG(load_method, MP_QSTR___aexit__, false);
EMIT_ARG(setup_except, try_exception_label); EMIT_ARG(setup_except, try_exception_label);
compile_increase_except_level(comp); compile_increase_except_level(comp);
...@@ -2219,9 +2219,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p ...@@ -2219,9 +2219,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p
return; return;
} }
// a super() call if (num_trail >= 3
EMIT_ARG(call_function, 2, 0, 0); && MP_PARSE_NODE_STRUCT_KIND(pns_trail[1]) == PN_trailer_period
i = 1; && MP_PARSE_NODE_STRUCT_KIND(pns_trail[2]) == PN_trailer_paren) {
// optimisation for method calls super().f(...), to eliminate heap allocation
mp_parse_node_struct_t *pns_period = pns_trail[1];
mp_parse_node_struct_t *pns_paren = pns_trail[2];
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), true);
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
i = 3;
} else {
// a super() call
EMIT_ARG(call_function, 2, 0, 0);
i = 1;
}
} }
// compile the remaining trailers // compile the remaining trailers
...@@ -2232,7 +2243,7 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p ...@@ -2232,7 +2243,7 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p
// optimisation for method calls a.f(...), following PyPy // optimisation for method calls a.f(...), following PyPy
mp_parse_node_struct_t *pns_period = pns_trail[i]; mp_parse_node_struct_t *pns_period = pns_trail[i];
mp_parse_node_struct_t *pns_paren = pns_trail[i + 1]; mp_parse_node_struct_t *pns_paren = pns_trail[i + 1];
EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0])); EMIT_ARG(load_method, MP_PARSE_NODE_LEAF_ARG(pns_period->nodes[0]), false);
compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0); compile_trailer_paren_helper(comp, pns_paren->nodes[0], true, 0);
i += 1; i += 1;
} else { } else {
......
...@@ -88,7 +88,7 @@ typedef struct _emit_method_table_t { ...@@ -88,7 +88,7 @@ typedef struct _emit_method_table_t {
void (*load_const_obj)(emit_t *emit, mp_obj_t obj); void (*load_const_obj)(emit_t *emit, mp_obj_t obj);
void (*load_null)(emit_t *emit); void (*load_null)(emit_t *emit);
void (*load_attr)(emit_t *emit, qstr qst); void (*load_attr)(emit_t *emit, qstr qst);
void (*load_method)(emit_t *emit, qstr qst); void (*load_method)(emit_t *emit, qstr qst, bool is_super);
void (*load_build_class)(emit_t *emit); void (*load_build_class)(emit_t *emit);
void (*load_subscr)(emit_t *emit); void (*load_subscr)(emit_t *emit);
void (*store_attr)(emit_t *emit, qstr qst); void (*store_attr)(emit_t *emit, qstr qst);
...@@ -205,7 +205,7 @@ void mp_emit_bc_load_const_str(emit_t *emit, qstr qst); ...@@ -205,7 +205,7 @@ void mp_emit_bc_load_const_str(emit_t *emit, qstr qst);
void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj); void mp_emit_bc_load_const_obj(emit_t *emit, mp_obj_t obj);
void mp_emit_bc_load_null(emit_t *emit); void mp_emit_bc_load_null(emit_t *emit);
void mp_emit_bc_load_attr(emit_t *emit, qstr qst); void mp_emit_bc_load_attr(emit_t *emit, qstr qst);
void mp_emit_bc_load_method(emit_t *emit, qstr qst); void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super);
void mp_emit_bc_load_build_class(emit_t *emit); void mp_emit_bc_load_build_class(emit_t *emit);
void mp_emit_bc_load_subscr(emit_t *emit); void mp_emit_bc_load_subscr(emit_t *emit);
void mp_emit_bc_store_attr(emit_t *emit, qstr qst); void mp_emit_bc_store_attr(emit_t *emit, qstr qst);
......
...@@ -594,9 +594,9 @@ void mp_emit_bc_load_attr(emit_t *emit, qstr qst) { ...@@ -594,9 +594,9 @@ void mp_emit_bc_load_attr(emit_t *emit, qstr qst) {
} }
} }
void mp_emit_bc_load_method(emit_t *emit, qstr qst) { void mp_emit_bc_load_method(emit_t *emit, qstr qst, bool is_super) {
emit_bc_pre(emit, 1); emit_bc_pre(emit, 1 - 2 * is_super);
emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_METHOD, qst); emit_write_bytecode_byte_qstr(emit, is_super ? MP_BC_LOAD_SUPER_METHOD : MP_BC_LOAD_METHOD, qst);
} }
void mp_emit_bc_load_build_class(emit_t *emit) { void mp_emit_bc_load_build_class(emit_t *emit) {
......
...@@ -85,6 +85,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { ...@@ -85,6 +85,7 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
[MP_F_LOAD_BUILD_CLASS] = 0, [MP_F_LOAD_BUILD_CLASS] = 0,
[MP_F_LOAD_ATTR] = 2, [MP_F_LOAD_ATTR] = 2,
[MP_F_LOAD_METHOD] = 3, [MP_F_LOAD_METHOD] = 3,
[MP_F_LOAD_SUPER_METHOD] = 2,
[MP_F_STORE_NAME] = 2, [MP_F_STORE_NAME] = 2,
[MP_F_STORE_GLOBAL] = 2, [MP_F_STORE_GLOBAL] = 2,
[MP_F_STORE_ATTR] = 3, [MP_F_STORE_ATTR] = 3,
...@@ -1065,12 +1066,18 @@ STATIC void emit_native_load_attr(emit_t *emit, qstr qst) { ...@@ -1065,12 +1066,18 @@ STATIC void emit_native_load_attr(emit_t *emit, qstr qst) {
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
} }
STATIC void emit_native_load_method(emit_t *emit, qstr qst) { STATIC void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) {
vtype_kind_t vtype_base; if (is_super) {
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr
assert(vtype_base == VTYPE_PYOBJ); emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr emit_call_with_imm_arg(emit, MP_F_LOAD_SUPER_METHOD, qst, REG_ARG_1); // arg1 = method name
emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name } else {
vtype_kind_t vtype_base;
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = base
assert(vtype_base == VTYPE_PYOBJ);
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, 2); // arg3 = dest ptr
emit_call_with_imm_arg(emit, MP_F_LOAD_METHOD, qst, REG_ARG_2); // arg2 = method name
}
} }
STATIC void emit_native_load_build_class(emit_t *emit) { STATIC void emit_native_load_build_class(emit_t *emit) {
......
...@@ -133,6 +133,7 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = { ...@@ -133,6 +133,7 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_load_build_class, mp_load_build_class,
mp_load_attr, mp_load_attr,
mp_load_method, mp_load_method,
mp_load_super_method,
mp_store_name, mp_store_name,
mp_store_global, mp_store_global,
mp_store_attr, mp_store_attr,
......
...@@ -1070,6 +1070,11 @@ const mp_obj_type_t mp_type_super = { ...@@ -1070,6 +1070,11 @@ const mp_obj_type_t mp_type_super = {
.attr = super_attr, .attr = super_attr,
}; };
void mp_load_super_method(qstr attr, mp_obj_t *dest) {
mp_obj_super_t super = {{&mp_type_super}, dest[1], dest[2]};
mp_load_method(MP_OBJ_FROM_PTR(&super), attr, dest);
}
/******************************************************************************/ /******************************************************************************/
// subclassing and built-ins specific to types // subclassing and built-ins specific to types
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#include "py/smallint.h" #include "py/smallint.h"
// The current version of .mpy files // The current version of .mpy files
#define MPY_VERSION (1) #define MPY_VERSION (2)
// The feature flags byte encodes the compile-time config options that // The feature flags byte encodes the compile-time config options that
// affect the generate bytecode. // affect the generate bytecode.
......
...@@ -131,6 +131,7 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); ...@@ -131,6 +131,7 @@ mp_obj_t mp_load_attr(mp_obj_t base, qstr attr);
void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest); void mp_convert_member_lookup(mp_obj_t obj, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest); void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest);
void mp_load_super_method(qstr attr, mp_obj_t *dest);
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val); void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t val);
mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf); mp_obj_t mp_getiter(mp_obj_t o, mp_obj_iter_buf_t *iter_buf);
......
...@@ -107,6 +107,7 @@ typedef enum { ...@@ -107,6 +107,7 @@ typedef enum {
MP_F_LOAD_BUILD_CLASS, MP_F_LOAD_BUILD_CLASS,
MP_F_LOAD_ATTR, MP_F_LOAD_ATTR,
MP_F_LOAD_METHOD, MP_F_LOAD_METHOD,
MP_F_LOAD_SUPER_METHOD,
MP_F_STORE_NAME, MP_F_STORE_NAME,
MP_F_STORE_GLOBAL, MP_F_STORE_GLOBAL,
MP_F_STORE_ATTR, MP_F_STORE_ATTR,
......
...@@ -245,6 +245,11 @@ const byte *mp_bytecode_print_str(const byte *ip) { ...@@ -245,6 +245,11 @@ const byte *mp_bytecode_print_str(const byte *ip) {
printf("LOAD_METHOD %s", qstr_str(qst)); printf("LOAD_METHOD %s", qstr_str(qst));
break; break;
case MP_BC_LOAD_SUPER_METHOD:
DECODE_QSTR;
printf("LOAD_SUPER_METHOD %s", qstr_str(qst));
break;
case MP_BC_LOAD_BUILD_CLASS: case MP_BC_LOAD_BUILD_CLASS:
printf("LOAD_BUILD_CLASS"); printf("LOAD_BUILD_CLASS");
break; break;
......
...@@ -376,6 +376,14 @@ dispatch_loop: ...@@ -376,6 +376,14 @@ dispatch_loop:
DISPATCH(); DISPATCH();
} }
ENTRY(MP_BC_LOAD_SUPER_METHOD): {
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
sp -= 1;
mp_load_super_method(qst, sp - 1);
DISPATCH();
}
ENTRY(MP_BC_LOAD_BUILD_CLASS): ENTRY(MP_BC_LOAD_BUILD_CLASS):
MARK_EXC_IP_SELECTIVE(); MARK_EXC_IP_SELECTIVE();
PUSH(mp_load_build_class()); PUSH(mp_load_build_class());
......
...@@ -44,6 +44,7 @@ static const void *const entry_table[256] = { ...@@ -44,6 +44,7 @@ static const void *const entry_table[256] = {
[MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL, [MP_BC_LOAD_GLOBAL] = &&entry_MP_BC_LOAD_GLOBAL,
[MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR, [MP_BC_LOAD_ATTR] = &&entry_MP_BC_LOAD_ATTR,
[MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD, [MP_BC_LOAD_METHOD] = &&entry_MP_BC_LOAD_METHOD,
[MP_BC_LOAD_SUPER_METHOD] = &&entry_MP_BC_LOAD_SUPER_METHOD,
[MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS, [MP_BC_LOAD_BUILD_CLASS] = &&entry_MP_BC_LOAD_BUILD_CLASS,
[MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR, [MP_BC_LOAD_SUBSCR] = &&entry_MP_BC_LOAD_SUBSCR,
[MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N, [MP_BC_STORE_FAST_N] = &&entry_MP_BC_STORE_FAST_N,
......
...@@ -57,7 +57,7 @@ class FreezeError(Exception): ...@@ -57,7 +57,7 @@ class FreezeError(Exception):
return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg) return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg)
class Config: class Config:
MPY_VERSION = 1 MPY_VERSION = 2
MICROPY_LONGINT_IMPL_NONE = 0 MICROPY_LONGINT_IMPL_NONE = 0
MICROPY_LONGINT_IMPL_LONGLONG = 1 MICROPY_LONGINT_IMPL_LONGLONG = 1
MICROPY_LONGINT_IMPL_MPZ = 2 MICROPY_LONGINT_IMPL_MPZ = 2
...@@ -94,7 +94,7 @@ def make_opcode_format(): ...@@ -94,7 +94,7 @@ def make_opcode_format():
OC4(U, U, U, U), # 0x0c-0x0f OC4(U, U, U, U), # 0x0c-0x0f
OC4(B, B, B, U), # 0x10-0x13 OC4(B, B, B, U), # 0x10-0x13
OC4(V, U, Q, V), # 0x14-0x17 OC4(V, U, Q, V), # 0x14-0x17
OC4(B, U, V, V), # 0x18-0x1b OC4(B, V, V, Q), # 0x18-0x1b
OC4(Q, Q, Q, Q), # 0x1c-0x1f OC4(Q, Q, Q, Q), # 0x1c-0x1f
OC4(B, B, V, V), # 0x20-0x23 OC4(B, B, V, V), # 0x20-0x23
OC4(Q, Q, Q, B), # 0x24-0x27 OC4(Q, Q, Q, B), # 0x24-0x27
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment