py: Properly implement deletion of locals and derefs, and detect errors.

Needed to reinstate 2 delete opcodes, to specifically check that a local
is not deleted twice.
This commit is contained in:
Damien George
2014-04-09 15:26:46 +01:00
parent 11d8cd54c9
commit 2bf7c09222
12 changed files with 130 additions and 33 deletions

View File

@@ -408,14 +408,20 @@ STATIC void emit_bc_load_null(emit_t *emit) {
emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL);
};
STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, int local_num) {
STATIC void emit_bc_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) {
assert(local_num >= 0);
emit_bc_pre(emit, 1);
switch (local_num) {
case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break;
case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break;
case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break;
default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
if (id_flags & ID_FLAG_IS_DELETED) {
// This local may be deleted, so need to do a checked load.
emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_CHECKED, local_num);
} else {
// This local is never deleted, so can do a fast, uncheched load.
switch (local_num) {
case 0: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_0); break;
case 1: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_1); break;
case 2: emit_write_byte_code_byte(emit, MP_BC_LOAD_FAST_2); break;
default: emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
}
}
}
@@ -491,13 +497,11 @@ STATIC void emit_bc_store_subscr(emit_t *emit) {
}
STATIC void emit_bc_delete_fast(emit_t *emit, qstr qstr, int local_num) {
emit_bc_load_null(emit);
emit_bc_store_fast(emit, qstr, local_num);
emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
}
STATIC void emit_bc_delete_deref(emit_t *emit, qstr qstr, int local_num) {
emit_bc_load_null(emit);
emit_bc_store_deref(emit, qstr, local_num);
emit_write_byte_code_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
}
STATIC void emit_bc_delete_name(emit_t *emit, qstr qstr) {