circuitpython/py/emitpass1.c
Damien George df8127a17e py: Remove unique_codes from emitglue.c. Replace with pointers.
Attempt to address issue #386.  unique_code_id's have been removed and
replaced with a pointer to the "raw code" information.  This pointer is
stored in the actual byte code (aligned, so the GC can trace it), so
that raw code (ie byte code, native code and inline assembler) is kept
only for as long as it is needed.  In memory it's now like a tree: the
outer module's byte code points directly to its children's raw code.  So
when the outer code gets freed, if there are no remaining functions that
need the raw code, then the children's code gets freed as well.

This is pretty much like CPython does it, except that CPython stores
indexes in the byte code rather than machine pointers.  These indices
index the per-function constant table in order to find the relevant
code.
2014-04-13 11:04:33 +01:00

194 lines
5.4 KiB
C

#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include "misc.h"
#include "mpconfig.h"
#include "qstr.h"
#include "lexer.h"
#include "parse.h"
#include "obj.h"
#include "emitglue.h"
#include "scope.h"
#include "runtime0.h"
#include "emit.h"
struct _emit_t {
scope_t *scope;
};
emit_t *emit_pass1_new(void) {
emit_t *emit = m_new(emit_t, 1);
return emit;
}
void emit_pass1_free(emit_t *emit) {
m_del_obj(emit_t, emit);
}
STATIC void emit_pass1_dummy(emit_t *emit) {
}
STATIC void emit_pass1_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
assert(pass == PASS_1);
emit->scope = scope;
}
STATIC void emit_pass1_end_pass(emit_t *emit) {
}
STATIC bool emit_pass1_last_emit_was_return_value(emit_t *emit) {
return false;
}
STATIC void emit_pass1_load_id(emit_t *emit, qstr qstr) {
// name adding/lookup
bool added;
id_info_t *id = scope_find_or_add_id(emit->scope, qstr, &added);
if (added) {
#if MICROPY_EMIT_CPYTHON
if (qstr == MP_QSTR_super && emit->scope->kind == SCOPE_FUNCTION) {
// special case, super is a global, and also counts as use of __class__
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
id_info_t *id2 = scope_find_local_in_parent(emit->scope, MP_QSTR___class__);
if (id2 != NULL) {
id2 = scope_find_or_add_id(emit->scope, MP_QSTR___class__, &added);
if (added) {
id2->kind = ID_INFO_KIND_FREE;
scope_close_over_in_parents(emit->scope, MP_QSTR___class__);
}
}
} else
#endif
{
id_info_t *id2 = scope_find_local_in_parent(emit->scope, qstr);
if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) {
id->kind = ID_INFO_KIND_FREE;
scope_close_over_in_parents(emit->scope, qstr);
} else {
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
}
}
}
}
STATIC id_info_t *get_id_for_modification(scope_t *scope, qstr qstr) {
// name adding/lookup
bool added;
id_info_t *id = scope_find_or_add_id(scope, qstr, &added);
if (added) {
if (scope->kind == SCOPE_MODULE || scope->kind == SCOPE_CLASS) {
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
} else {
id->kind = ID_INFO_KIND_LOCAL;
}
} else if (scope->kind >= SCOPE_FUNCTION && scope->kind <= SCOPE_GEN_EXPR && id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
// rebind as a local variable
id->kind = ID_INFO_KIND_LOCAL;
}
assert(id != NULL); // TODO can this ever fail?
return id;
}
STATIC void emit_pass1_store_id(emit_t *emit, qstr qstr) {
get_id_for_modification(emit->scope, qstr);
}
STATIC void emit_pass1_delete_id(emit_t *emit, qstr qstr) {
id_info_t *id = get_id_for_modification(emit->scope, qstr);
// this flag is unused
//id->flags |= ID_FLAG_IS_DELETED;
(void)id; // suppress compiler warning
}
const emit_method_table_t emit_pass1_method_table = {
(void*)emit_pass1_dummy,
emit_pass1_start_pass,
emit_pass1_end_pass,
emit_pass1_last_emit_was_return_value,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
emit_pass1_load_id,
emit_pass1_store_id,
emit_pass1_delete_id,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
(void*)emit_pass1_dummy,
};