summaryrefslogtreecommitdiffstatshomepage
path: root/py/emitbc.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-10-25 15:07:02 +0100
committerDamien George <damien.p.george@gmail.com>2014-10-25 20:23:13 +0100
commit1084b0f9c21b093618da4494508dec9ca8467e35 (patch)
treee21a6e19240346b6a449b432cbf961d7839fba4b /py/emitbc.c
parentfcff4663dd5bd33eed931c7731fd133f49551b4b (diff)
downloadmicropython-1084b0f9c21b093618da4494508dec9ca8467e35.tar.gz
micropython-1084b0f9c21b093618da4494508dec9ca8467e35.zip
py: Store bytecode arg names in bytecode (were in own array).
This saves a lot of RAM for 2 reasons: 1. For functions that don't have default values, var args or var kw args (which is a large number of functions in the general case), the mp_obj_fun_bc_t type now fits in 1 GC block (previously needed 2 because of the extra pointer to point to the arg_names array). So this saves 16 bytes per function (32 bytes on 64-bit machines). 2. Combining separate memory regions generally saves RAM because the unused bytes at the end of the GC block are saved for 1 of the blocks (since that block doesn't exist on its own anymore). So generally this saves 8 bytes per function. Tested by importing lots of modules: - 64-bit Linux gave about an 8% RAM saving for 86k of used RAM. - pyboard gave about a 6% RAM saving for 31k of used RAM.
Diffstat (limited to 'py/emitbc.c')
-rw-r--r--py/emitbc.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/py/emitbc.c b/py/emitbc.c
index 05dc79ef4f..cee6d3396c 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -218,6 +218,13 @@ STATIC void emit_write_bytecode_byte_uint(emit_t* emit, byte b, mp_uint_t val) {
emit_write_uint(emit, emit_get_cur_to_write_bytecode, val);
}
+STATIC void emit_write_bytecode_prealigned_ptr(emit_t* emit, void *ptr) {
+ mp_uint_t *c = (mp_uint_t*)emit_get_cur_to_write_bytecode(emit, sizeof(mp_uint_t));
+ // Verify thar c is already uint-aligned
+ assert(c == MP_ALIGN(c, sizeof(mp_uint_t)));
+ *c = (mp_uint_t)ptr;
+}
+
// aligns the pointer so it is friendly to GC
STATIC void emit_write_bytecode_byte_ptr(emit_t* emit, byte b, void *ptr) {
emit_write_bytecode_byte(emit, b);
@@ -294,7 +301,16 @@ STATIC void emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
emit_write_code_info_qstr(emit, scope->simple_name);
emit_write_code_info_qstr(emit, scope->source_file);
- // bytecode prelude: local state size and exception stack size; 16 bit uints for now
+ // bytecode prelude: argument names (needed to resolve positional args passed as keywords)
+ // we store them as full word-sized objects for efficient access in mp_setup_code_state
+ // this is the start of the prelude and is guaranteed to be aligned on a word boundary
+ {
+ for (int i = 0; i < scope->num_pos_args + scope->num_kwonly_args; i++) {
+ emit_write_bytecode_prealigned_ptr(emit, MP_OBJ_NEW_QSTR(scope->id_info[i].qst));
+ }
+ }
+
+ // bytecode prelude: local state size and exception stack size
{
mp_uint_t n_state = scope->num_locals + scope->stack_size;
if (n_state == 0) {
@@ -358,13 +374,9 @@ STATIC void emit_bc_end_pass(emit_t *emit) {
emit->code_base = m_new0(byte, emit->code_info_size + emit->bytecode_size);
} else if (emit->pass == MP_PASS_EMIT) {
- qstr *arg_names = m_new(qstr, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
- for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
- arg_names[i] = emit->scope->id_info[i].qst;
- }
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
emit->code_info_size + emit->bytecode_size,
- emit->scope->num_pos_args, emit->scope->num_kwonly_args, arg_names,
+ emit->scope->num_pos_args, emit->scope->num_kwonly_args,
emit->scope->scope_flags);
}
}