summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/asmarm.c5
-rw-r--r--py/asmarm.h15
-rw-r--r--py/asmbase.c6
-rw-r--r--py/asmthumb.c5
-rw-r--r--py/asmthumb.h16
-rw-r--r--py/asmx64.c4
-rw-r--r--py/asmx64.h15
-rw-r--r--py/asmx86.c3
-rw-r--r--py/asmx86.h17
-rw-r--r--py/asmxtensa.h15
-rw-r--r--py/builtinhelp.c4
-rwxr-xr-xpy/builtinimport.c47
-rw-r--r--py/compile.c338
-rw-r--r--py/emit.h126
-rw-r--r--py/emitbc.c304
-rw-r--r--py/emitcommon.c8
-rw-r--r--py/emitglue.c5
-rw-r--r--py/emitglue.h7
-rw-r--r--py/emitnarm.c15
-rw-r--r--py/emitnative.c493
-rw-r--r--py/emitnthumb.c15
-rw-r--r--py/emitnx64.c15
-rw-r--r--py/emitnx86.c68
-rw-r--r--py/emitnxtensa.c15
-rw-r--r--py/formatfloat.c10
-rwxr-xr-xpy/gc.c124
-rw-r--r--py/gc.h4
-rw-r--r--py/grammar.h22
-rw-r--r--py/lexer.c2
-rw-r--r--py/makeqstrdata.py3
-rw-r--r--py/makeqstrdefs.py10
-rw-r--r--py/makeversionhdr.py2
-rw-r--r--py/malloc.c18
-rw-r--r--py/map.c14
-rw-r--r--py/misc.h27
-rw-r--r--py/mkenv.mk4
-rw-r--r--py/mkrules.mk37
-rw-r--r--py/modbuiltins.c172
-rw-r--r--py/modcollections.c3
-rw-r--r--py/modio.c75
-rw-r--r--py/modmicropython.c22
-rw-r--r--py/modsys.c7
-rw-r--r--py/modthread.c6
-rwxr-xr-xpy/mpconfig.h138
-rw-r--r--py/mperrno.h2
-rw-r--r--py/mpprint.c28
-rw-r--r--py/mpstate.h53
-rw-r--r--py/mpz.c147
-rw-r--r--py/mpz.h4
-rw-r--r--py/nativeglue.c2
-rw-r--r--py/nlr.c51
-rw-r--r--py/nlr.h87
-rw-r--r--py/nlrsetjmp.c7
-rw-r--r--py/nlrthumb.c39
-rw-r--r--py/nlrx64.c35
-rw-r--r--py/nlrx86.c57
-rw-r--r--py/nlrxtensa.c25
-rw-r--r--py/obj.h45
-rw-r--r--py/objarray.c11
-rw-r--r--py/objarray.h3
-rw-r--r--py/objboundmeth.c8
-rw-r--r--py/objdeque.c167
-rw-r--r--py/objdict.c58
-rw-r--r--py/objexcept.c36
-rw-r--r--py/objexcept.h13
-rw-r--r--py/objfloat.c18
-rw-r--r--py/objfun.c65
-rw-r--r--py/objgenerator.c47
-rw-r--r--py/objint.c23
-rw-r--r--py/objint_longlong.c14
-rw-r--r--py/objint_mpz.c8
-rw-r--r--py/objlist.h2
-rw-r--r--py/objmodule.c28
-rw-r--r--py/objmodule.h9
-rw-r--r--py/objnamedtuple.c52
-rw-r--r--py/objnamedtuple.h26
-rw-r--r--py/objobject.c9
-rw-r--r--py/objrange.c21
-rw-r--r--py/objset.c8
-rw-r--r--py/objstr.c89
-rw-r--r--py/objstr.h1
-rw-r--r--py/objstringio.c30
-rw-r--r--py/objstrunicode.c6
-rw-r--r--py/objtype.c318
-rw-r--r--py/objtype.h6
-rw-r--r--py/opmethods.c4
-rw-r--r--py/parse.c307
-rw-r--r--py/parsenum.c56
-rw-r--r--py/persistentcode.c6
-rw-r--r--py/py.mk108
-rw-r--r--py/pystack.c57
-rw-r--r--py/pystack.h123
-rwxr-xr-xpy/qstr.c35
-rw-r--r--py/qstr.h4
-rw-r--r--py/qstrdefs.h5
-rw-r--r--py/reader.c3
-rw-r--r--py/repl.c87
-rw-r--r--py/runtime.c126
-rw-r--r--py/runtime.h10
-rw-r--r--py/runtime0.h6
-rw-r--r--py/runtime_utils.c12
-rw-r--r--py/smallint.h6
-rw-r--r--py/stackctrl.c6
-rw-r--r--py/stream.c49
-rw-r--r--py/stream.h20
-rw-r--r--py/unicode.c29
-rw-r--r--py/vm.c192
107 files changed, 3109 insertions, 2061 deletions
diff --git a/py/asmarm.c b/py/asmarm.c
index 552fdfb34..1a8923bc2 100644
--- a/py/asmarm.c
+++ b/py/asmarm.c
@@ -150,10 +150,7 @@ void asm_arm_bkpt(asm_arm_t *as) {
// | low address | high address in RAM
void asm_arm_entry(asm_arm_t *as, int num_locals) {
-
- if (num_locals < 0) {
- num_locals = 0;
- }
+ assert(num_locals >= 0);
as->stack_adjust = 0;
as->push_reglist = 1 << ASM_ARM_REG_R1
diff --git a/py/asmarm.h b/py/asmarm.h
index 9392a0fae..fbfe09aac 100644
--- a/py/asmarm.h
+++ b/py/asmarm.h
@@ -167,17 +167,12 @@ void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
} while (0)
#define ASM_CALL_IND(as, ptr, idx) asm_arm_bl_ind(as, ptr, idx, ASM_ARM_REG_R3)
-#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_arm_mov_local_reg(as, (local_num), (reg))
-#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
-#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_arm_mov_reg_i32(as, (reg), (imm))
-#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
- do { \
- asm_arm_mov_reg_i32(as, (reg_temp), (imm)); \
- asm_arm_mov_local_reg(as, (local_num), (reg_temp)); \
- } while (false)
-#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_arm_mov_reg_local(as, (reg), (local_num))
+#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_arm_mov_local_reg((as), (local_num), (reg_src))
+#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm))
+#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_arm_mov_reg_i32((as), (reg_dest), (imm))
+#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_arm_mov_reg_local((as), (reg_dest), (local_num))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_arm_mov_reg_reg((as), (reg_dest), (reg_src))
-#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_arm_mov_reg_local_addr(as, (reg), (local_num))
+#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_arm_mov_reg_local_addr((as), (reg_dest), (local_num))
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_arm_lsl_reg_reg((as), (reg_dest), (reg_shift))
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_arm_asr_reg_reg((as), (reg_dest), (reg_shift))
diff --git a/py/asmbase.c b/py/asmbase.c
index c941e917b..4c84c3b25 100644
--- a/py/asmbase.c
+++ b/py/asmbase.c
@@ -46,10 +46,10 @@ void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) {
}
void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {
- if (pass == MP_ASM_PASS_COMPUTE) {
- // reset all labels
+ if (pass < MP_ASM_PASS_EMIT) {
+ // Reset labels so we can detect backwards jumps (and verify unique assignment)
memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t));
- } else if (pass == MP_ASM_PASS_EMIT) {
+ } else {
// allocating executable RAM is platform specific
MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size);
assert(as->code_base != NULL);
diff --git a/py/asmthumb.c b/py/asmthumb.c
index 5316a7efb..c5b45f2f5 100644
--- a/py/asmthumb.c
+++ b/py/asmthumb.c
@@ -104,6 +104,8 @@ STATIC void asm_thumb_write_word32(asm_thumb_t *as, int w32) {
// | low address | high address in RAM
void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
+ assert(num_locals >= 0);
+
// work out what to push and how many extra spaces to reserve on stack
// so that we have enough for all locals and it's aligned an 8-byte boundary
// we push extra regs (r1, r2, r3) to help do the stack adjustment
@@ -111,9 +113,6 @@ void asm_thumb_entry(asm_thumb_t *as, int num_locals) {
// for push rlist, lowest numbered register at the lowest address
uint reglist;
uint stack_adjust;
- if (num_locals < 0) {
- num_locals = 0;
- }
// don't pop r0 because it's used for return value
switch (num_locals) {
case 0:
diff --git a/py/asmthumb.h b/py/asmthumb.h
index a19c11b2c..f8665f35c 100644
--- a/py/asmthumb.h
+++ b/py/asmthumb.h
@@ -26,6 +26,7 @@
#ifndef MICROPY_INCLUDED_PY_ASMTHUMB_H
#define MICROPY_INCLUDED_PY_ASMTHUMB_H
+#include <assert.h>
#include "py/misc.h"
#include "py/asmbase.h"
@@ -283,17 +284,12 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
} while (0)
#define ASM_CALL_IND(as, ptr, idx) asm_thumb_bl_ind(as, ptr, idx, ASM_THUMB_REG_R3)
-#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_thumb_mov_local_reg(as, (local_num), (reg))
-#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_optimised(as, (reg), (imm))
-#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_thumb_mov_reg_i32_aligned(as, (reg), (imm))
-#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
- do { \
- asm_thumb_mov_reg_i32_optimised(as, (reg_temp), (imm)); \
- asm_thumb_mov_local_reg(as, (local_num), (reg_temp)); \
- } while (false)
-#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local(as, (reg), (local_num))
+#define ASM_MOV_LOCAL_REG(as, local_num, reg) asm_thumb_mov_local_reg((as), (local_num), (reg))
+#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_optimised((as), (reg_dest), (imm))
+#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_thumb_mov_reg_i32_aligned((as), (reg_dest), (imm))
+#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_thumb_mov_reg_local((as), (reg_dest), (local_num))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_thumb_mov_reg_reg((as), (reg_dest), (reg_src))
-#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_thumb_mov_reg_local_addr(as, (reg), (local_num))
+#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_thumb_mov_reg_local_addr((as), (reg_dest), (local_num))
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_LSL, (reg_dest), (reg_shift))
#define ASM_ASR_REG_REG(as, reg_dest, reg_shift) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_ASR, (reg_dest), (reg_shift))
diff --git a/py/asmx64.c b/py/asmx64.c
index aa2a8ec7c..c900a08d1 100644
--- a/py/asmx64.c
+++ b/py/asmx64.c
@@ -526,11 +526,9 @@ void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) {
}
void asm_x64_entry(asm_x64_t *as, int num_locals) {
+ assert(num_locals >= 0);
asm_x64_push_r64(as, ASM_X64_REG_RBP);
asm_x64_mov_r64_r64(as, ASM_X64_REG_RBP, ASM_X64_REG_RSP);
- if (num_locals < 0) {
- num_locals = 0;
- }
num_locals |= 1; // make it odd so stack is aligned on 16 byte boundary
asm_x64_sub_r64_i32(as, ASM_X64_REG_RSP, num_locals * WORD_SIZE);
asm_x64_push_r64(as, ASM_X64_REG_RBX);
diff --git a/py/asmx64.h b/py/asmx64.h
index bf8bbd162..9ed2a6cf9 100644
--- a/py/asmx64.h
+++ b/py/asmx64.h
@@ -162,17 +162,12 @@ void asm_x64_call_ind(asm_x64_t* as, void* ptr, int temp_r32);
} while (0)
#define ASM_CALL_IND(as, ptr, idx) asm_x64_call_ind(as, ptr, ASM_X64_REG_RAX)
-#define ASM_MOV_REG_TO_LOCAL asm_x64_mov_r64_to_local
-#define ASM_MOV_IMM_TO_REG asm_x64_mov_i64_to_r64_optimised
-#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x64_mov_i64_to_r64_aligned
-#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
- do { \
- asm_x64_mov_i64_to_r64_optimised(as, (imm), (reg_temp)); \
- asm_x64_mov_r64_to_local(as, (reg_temp), (local_num)); \
- } while (false)
-#define ASM_MOV_LOCAL_TO_REG asm_x64_mov_local_to_r64
+#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x64_mov_r64_to_local((as), (reg_src), (local_num))
+#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_optimised((as), (imm), (reg_dest))
+#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x64_mov_i64_to_r64_aligned((as), (imm), (reg_dest))
+#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x64_mov_local_to_r64((as), (local_num), (reg_dest))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x64_mov_r64_r64((as), (reg_dest), (reg_src))
-#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x64_mov_local_addr_to_r64
+#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x64_mov_local_addr_to_r64((as), (local_num), (reg_dest))
#define ASM_LSL_REG(as, reg) asm_x64_shl_r64_cl((as), (reg))
#define ASM_ASR_REG(as, reg) asm_x64_sar_r64_cl((as), (reg))
diff --git a/py/asmx86.c b/py/asmx86.c
index 6a78fbd5e..3938baaac 100644
--- a/py/asmx86.c
+++ b/py/asmx86.c
@@ -387,7 +387,8 @@ void asm_x86_jcc_label(asm_x86_t *as, mp_uint_t jcc_type, mp_uint_t label) {
}
}
-void asm_x86_entry(asm_x86_t *as, mp_uint_t num_locals) {
+void asm_x86_entry(asm_x86_t *as, int num_locals) {
+ assert(num_locals >= 0);
asm_x86_push_r32(as, ASM_X86_REG_EBP);
asm_x86_mov_r32_r32(as, ASM_X86_REG_EBP, ASM_X86_REG_ESP);
if (num_locals > 0) {
diff --git a/py/asmx86.h b/py/asmx86.h
index a5902987c..eb6c03eac 100644
--- a/py/asmx86.h
+++ b/py/asmx86.h
@@ -104,7 +104,7 @@ void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b);
void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8);
void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label);
void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label);
-void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals);
+void asm_x86_entry(asm_x86_t* as, int num_locals);
void asm_x86_exit(asm_x86_t* as);
void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32);
void asm_x86_mov_local_to_r32(asm_x86_t* as, int src_local_num, int dest_r32);
@@ -160,17 +160,12 @@ void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32);
} while (0)
#define ASM_CALL_IND(as, ptr, idx) asm_x86_call_ind(as, ptr, mp_f_n_args[idx], ASM_X86_REG_EAX)
-#define ASM_MOV_REG_TO_LOCAL asm_x86_mov_r32_to_local
-#define ASM_MOV_IMM_TO_REG asm_x86_mov_i32_to_r32
-#define ASM_MOV_ALIGNED_IMM_TO_REG asm_x86_mov_i32_to_r32_aligned
-#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
- do { \
- asm_x86_mov_i32_to_r32(as, (imm), (reg_temp)); \
- asm_x86_mov_r32_to_local(as, (reg_temp), (local_num)); \
- } while (false)
-#define ASM_MOV_LOCAL_TO_REG asm_x86_mov_local_to_r32
+#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_x86_mov_r32_to_local((as), (reg_src), (local_num))
+#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32((as), (imm), (reg_dest))
+#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_x86_mov_i32_to_r32_aligned((as), (imm), (reg_dest))
+#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_x86_mov_local_to_r32((as), (local_num), (reg_dest))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_x86_mov_r32_r32((as), (reg_dest), (reg_src))
-#define ASM_MOV_LOCAL_ADDR_TO_REG asm_x86_mov_local_addr_to_r32
+#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_x86_mov_local_addr_to_r32((as), (local_num), (reg_dest))
#define ASM_LSL_REG(as, reg) asm_x86_shl_r32_cl((as), (reg))
#define ASM_ASR_REG(as, reg) asm_x86_sar_r32_cl((as), (reg))
diff --git a/py/asmxtensa.h b/py/asmxtensa.h
index 69de24b81..13d3e8234 100644
--- a/py/asmxtensa.h
+++ b/py/asmxtensa.h
@@ -280,17 +280,12 @@ void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_nu
asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0); \
} while (0)
-#define ASM_MOV_REG_TO_LOCAL(as, reg, local_num) asm_xtensa_mov_local_reg(as, (local_num), (reg))
-#define ASM_MOV_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm))
-#define ASM_MOV_ALIGNED_IMM_TO_REG(as, imm, reg) asm_xtensa_mov_reg_i32(as, (reg), (imm))
-#define ASM_MOV_IMM_TO_LOCAL_USING(as, imm, local_num, reg_temp) \
- do { \
- asm_xtensa_mov_reg_i32(as, (reg_temp), (imm)); \
- asm_xtensa_mov_local_reg(as, (local_num), (reg_temp)); \
- } while (0)
-#define ASM_MOV_LOCAL_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local(as, (reg), (local_num))
+#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src))
+#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))
+#define ASM_MOV_REG_ALIGNED_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))
+#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src))
-#define ASM_MOV_LOCAL_ADDR_TO_REG(as, local_num, reg) asm_xtensa_mov_reg_local_addr(as, (reg), (local_num))
+#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num))
#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \
do { \
diff --git a/py/builtinhelp.c b/py/builtinhelp.c
index 1cea8caac..4cea7e6d5 100644
--- a/py/builtinhelp.c
+++ b/py/builtinhelp.c
@@ -70,7 +70,7 @@ STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) {
while (*name) {
size_t l = strlen(name);
// name should end in '.py' and we strip it off
- mp_obj_list_append(list, mp_obj_new_str(name, l - 3, false));
+ mp_obj_list_append(list, mp_obj_new_str(name, l - 3));
name += l + 1;
}
}
@@ -109,7 +109,7 @@ STATIC void mp_help_print_modules(void) {
// print the list of modules in a column-first order
#define NUM_COLUMNS (4)
#define COLUMN_WIDTH (18)
- mp_uint_t len;
+ size_t len;
mp_obj_t *items;
mp_obj_list_get(list, &len, &items);
unsigned int num_rows = (len + NUM_COLUMNS - 1) / NUM_COLUMNS;
diff --git a/py/builtinimport.c b/py/builtinimport.c
index c1437da4c..649cd11ef 100755
--- a/py/builtinimport.c
+++ b/py/builtinimport.c
@@ -46,6 +46,8 @@
#define DEBUG_printf(...) (void)0
#endif
+#if MICROPY_ENABLE_EXTERNAL_IMPORT
+
#define PATH_SEP_CHAR '/'
bool mp_obj_is_package(mp_obj_t module) {
@@ -335,7 +337,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
}
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
- char *new_mod = alloca(new_mod_l);
+ char *new_mod = mp_local_alloc(new_mod_l);
memcpy(new_mod, this_name, p - this_name);
if (mod_len != 0) {
new_mod[p - this_name] = '.';
@@ -343,9 +345,10 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
}
qstr new_mod_q = qstr_from_strn(new_mod, new_mod_l);
+ mp_local_free(new_mod);
DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q));
module_name = MP_OBJ_NEW_QSTR(new_mod_q);
- mod_str = new_mod;
+ mod_str = qstr_str(new_mod_q);
mod_len = new_mod_l;
}
@@ -406,6 +409,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
}
// found weak linked module
module_obj = el->value;
+ mp_module_call_init(mod_name, module_obj);
} else {
no_exist:
#else
@@ -452,7 +456,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path));
// https://docs.python.org/3/reference/import.html
// "Specifically, any module that contains a __path__ attribute is considered a package."
- mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false));
+ mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path)));
size_t orig_path_len = path.len;
vstr_add_char(&path, PATH_SEP_CHAR);
vstr_add_str(&path, "__init__.py");
@@ -497,4 +501,41 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
// Otherwise, we need to return top-level package
return top_module_obj;
}
+
+#else // MICROPY_ENABLE_EXTERNAL_IMPORT
+
+mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
+ // Check that it's not a relative import
+ if (n_args >= 5 && MP_OBJ_SMALL_INT_VALUE(args[4]) != 0) {
+ mp_raise_NotImplementedError("relative import");
+ }
+
+ // Check if module already exists, and return it if it does
+ qstr module_name_qstr = mp_obj_str_get_qstr(args[0]);
+ mp_obj_t module_obj = mp_module_get(module_name_qstr);
+ if (module_obj != MP_OBJ_NULL) {
+ return module_obj;
+ }
+
+ #if MICROPY_MODULE_WEAK_LINKS
+ // Check if there is a weak link to this module
+ mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_map, MP_OBJ_NEW_QSTR(module_name_qstr), MP_MAP_LOOKUP);
+ if (el != NULL) {
+ // Found weak-linked module
+ mp_module_call_init(module_name_qstr, el->value);
+ return el->value;
+ }
+ #endif
+
+ // Couldn't find the module, so fail
+ if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
+ mp_raise_msg(&mp_type_ImportError, "module not found");
+ } else {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError,
+ "no module named '%q'", module_name_qstr));
+ }
+}
+
+#endif // MICROPY_ENABLE_EXTERNAL_IMPORT
+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj, 1, 5, mp_builtin___import__);
diff --git a/py/compile.c b/py/compile.c
index 4e704abfb..7daf91103 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -65,16 +65,16 @@ typedef enum {
// we need a method table to do the lookup for the emitter functions
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__))
-#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num))
-#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst))
+#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST))
+#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL))
#else
// if we only have the bytecode emitter enabled then we can do a direct call to the functions
#define EMIT(fun) (mp_emit_bc_##fun(comp->emit))
#define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__))
-#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num))
-#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst))
+#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_local(comp->emit, qst, local_num, MP_EMIT_IDOP_LOCAL_FAST))
+#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL))
#endif
@@ -273,7 +273,7 @@ STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t
}
total += n;
}
- EMIT_ARG(build_tuple, total);
+ EMIT_ARG(build, total, MP_EMIT_BUILD_TUPLE);
}
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -366,37 +366,32 @@ STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, as
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
if (assign_kind == ASSIGN_AUG_STORE) {
EMIT(rot_three);
- EMIT(store_subscr);
+ EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE);
} else {
compile_node(comp, pns1->nodes[0]);
if (assign_kind == ASSIGN_AUG_LOAD) {
EMIT(dup_top_two);
- EMIT(load_subscr);
+ EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD);
} else {
- EMIT(store_subscr);
+ EMIT_ARG(subscr, MP_EMIT_SUBSCR_STORE);
}
}
+ return;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {
assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
if (assign_kind == ASSIGN_AUG_LOAD) {
EMIT(dup_top);
- EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_LOAD);
} else {
if (assign_kind == ASSIGN_AUG_STORE) {
EMIT(rot_two);
}
- EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_STORE);
}
- } else {
- goto cannot_assign;
+ return;
}
- } else {
- goto cannot_assign;
}
- return;
-
-cannot_assign:
compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression");
}
@@ -657,12 +652,12 @@ STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn)
// in MicroPython we put the default positional parameters into a tuple using the bytecode
// we need to do this here before we start building the map for the default keywords
if (comp->num_default_params > 0) {
- EMIT_ARG(build_tuple, comp->num_default_params);
+ EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE);
} else {
EMIT(load_null); // sentinel indicating empty default positional args
}
// first default dict param, so make the map
- EMIT_ARG(build_map, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);
}
// compile value then key, then store it to the dict
@@ -698,7 +693,7 @@ STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_n
// in MicroPython we put the default positional parameters into a tuple using the bytecode
// the default keywords args may have already made the tuple; if not, do it now
if (comp->num_default_params > 0 && comp->num_dict_params == 0) {
- EMIT_ARG(build_tuple, comp->num_default_params);
+ EMIT_ARG(build, comp->num_default_params, MP_EMIT_BUILD_TUPLE);
EMIT(load_null); // sentinel indicating empty default keyword args
}
@@ -825,7 +820,7 @@ STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_node(comp, name_nodes[0]);
for (int j = 1; j < name_len; j++) {
assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be
- EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]));
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]), MP_EMIT_ATTR_LOAD);
}
// nodes[1] contains arguments to the decorator function, if any
@@ -889,10 +884,10 @@ STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
}
if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
compile_node(comp, pns1->nodes[0]);
- EMIT(delete_subscr);
+ EMIT_ARG(subscr, MP_EMIT_SUBSCR_DELETE);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {
assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
- EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]), MP_EMIT_ATTR_DELETE);
} else {
goto cannot_delete;
}
@@ -950,20 +945,21 @@ STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt);
}
-STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
- if (comp->break_label == INVALID_LABEL) {
- compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop");
+STATIC void compile_break_cont_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ uint16_t label;
+ const char *error_msg;
+ if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_break_stmt) {
+ label = comp->break_label;
+ error_msg = "'break' outside loop";
+ } else {
+ label = comp->continue_label;
+ error_msg = "'continue' outside loop";
}
- assert(comp->cur_except_level >= comp->break_continue_except_level);
- EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level);
-}
-
-STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
- if (comp->continue_label == INVALID_LABEL) {
- compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop");
+ if (label == INVALID_LABEL) {
+ compile_syntax_error(comp, (mp_parse_node_t)pns, error_msg);
}
assert(comp->cur_except_level >= comp->break_continue_except_level);
- EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level);
+ EMIT_ARG(unwind_jump, label, comp->cur_except_level - comp->break_continue_except_level);
}
STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -1029,14 +1025,14 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
if (MP_PARSE_NODE_IS_NULL(pn)) {
// empty name (eg, from . import x)
*q_base = MP_QSTR_;
- EMIT_ARG(import_name, MP_QSTR_); // import the empty string
+ EMIT_ARG(import, MP_QSTR_, MP_EMIT_IMPORT_NAME); // import the empty string
} else if (MP_PARSE_NODE_IS_ID(pn)) {
// just a simple name
qstr q_full = MP_PARSE_NODE_LEAF_ARG(pn);
if (!is_as) {
*q_base = q_full;
}
- EMIT_ARG(import_name, q_full);
+ EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME);
} else {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_name)); // should be
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
@@ -1050,8 +1046,8 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
for (int i = 0; i < n; i++) {
len += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
}
- byte *q_ptr;
- byte *str_dest = qstr_build_start(len, &q_ptr);
+ char *q_ptr = mp_local_alloc(len);
+ char *str_dest = q_ptr;
for (int i = 0; i < n; i++) {
if (i > 0) {
*str_dest++ = '.';
@@ -1061,11 +1057,12 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
memcpy(str_dest, str_src, str_src_len);
str_dest += str_src_len;
}
- qstr q_full = qstr_build_end(q_ptr);
- EMIT_ARG(import_name, q_full);
+ qstr q_full = qstr_from_strn(q_ptr, len);
+ mp_local_free(q_ptr);
+ EMIT_ARG(import, q_full, MP_EMIT_IMPORT_NAME);
if (is_as) {
for (int i = 1; i < n; i++) {
- EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), MP_EMIT_ATTR_LOAD);
}
}
}
@@ -1126,12 +1123,12 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
// build the "fromlist" tuple
EMIT_ARG(load_const_str, MP_QSTR__star_);
- EMIT_ARG(build_tuple, 1);
+ EMIT_ARG(build, 1, MP_EMIT_BUILD_TUPLE);
// do the import
qstr dummy_q;
do_import_name(comp, pn_import_source, &dummy_q);
- EMIT(import_star);
+ EMIT_ARG(import, MP_QSTR_NULL, MP_EMIT_IMPORT_STAR);
} else {
EMIT_ARG(load_const_small_int, import_level);
@@ -1145,7 +1142,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id
EMIT_ARG(load_const_str, id2);
}
- EMIT_ARG(build_tuple, n);
+ EMIT_ARG(build, n, MP_EMIT_BUILD_TUPLE);
// do the import
qstr dummy_q;
@@ -1154,7 +1151,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i];
qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id
- EMIT_ARG(import_from, id2);
+ EMIT_ARG(import, id2, MP_EMIT_IMPORT_FROM);
if (MP_PARSE_NODE_IS_NULL(pns3->nodes[1])) {
compile_store_id(comp, id2);
} else {
@@ -1165,9 +1162,7 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
-STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
- bool added;
- id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
+STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) {
if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) {
compile_syntax_error(comp, pn, "identifier redefined as global");
return;
@@ -1181,19 +1176,7 @@ STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qs
}
}
-STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
- if (comp->pass == MP_PASS_SCOPE) {
- mp_parse_node_t *nodes;
- int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes);
- for (int i = 0; i < n; i++) {
- compile_declare_global(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i]));
- }
- }
-}
-
-STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
- bool added;
- id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
+STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst, bool added, id_info_t *id_info) {
if (added) {
scope_find_local_and_close_over(comp->scope_cur, id_info, qst);
if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
@@ -1204,16 +1187,26 @@ STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr
}
}
-STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
+STATIC void compile_global_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (comp->pass == MP_PASS_SCOPE) {
- if (comp->scope_cur->kind == SCOPE_MODULE) {
+ bool is_global = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_global_stmt;
+
+ if (!is_global && comp->scope_cur->kind == SCOPE_MODULE) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "can't declare nonlocal in outer code");
return;
}
+
mp_parse_node_t *nodes;
int n = mp_parse_node_extract_list(&pns->nodes[0], PN_name_list, &nodes);
for (int i = 0; i < n; i++) {
- compile_declare_nonlocal(comp, (mp_parse_node_t)pns, MP_PARSE_NODE_LEAF_ARG(nodes[i]));
+ qstr qst = MP_PARSE_NODE_LEAF_ARG(nodes[i]);
+ bool added;
+ id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
+ if (is_global) {
+ compile_declare_global(comp, (mp_parse_node_t)pns, qst, added, id_info);
+ } else {
+ compile_declare_nonlocal(comp, (mp_parse_node_t)pns, qst, added, id_info);
+ }
}
}
}
@@ -1520,7 +1513,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
uint l1 = comp_next_label(comp);
uint success_label = comp_next_label(comp);
- EMIT_ARG(setup_except, l1);
+ EMIT_ARG(setup_block, l1, MP_EMIT_SETUP_BLOCK_EXCEPT);
compile_increase_except_level(comp);
compile_node(comp, pn_body); // body
@@ -1575,7 +1568,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
uint l3 = 0;
if (qstr_exception_local != 0) {
l3 = comp_next_label(comp);
- EMIT_ARG(setup_finally, l3);
+ EMIT_ARG(setup_block, l3, MP_EMIT_SETUP_BLOCK_FINALLY);
compile_increase_except_level(comp);
}
compile_node(comp, pns_except->nodes[1]);
@@ -1610,7 +1603,7 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n_except, mp_parse_node_t *pn_except, mp_parse_node_t pn_else, mp_parse_node_t pn_finally) {
uint l_finally_block = comp_next_label(comp);
- EMIT_ARG(setup_finally, l_finally_block);
+ EMIT_ARG(setup_block, l_finally_block, MP_EMIT_SETUP_BLOCK_FINALLY);
compile_increase_except_level(comp);
if (n_except == 0) {
@@ -1672,12 +1665,12 @@ STATIC void compile_with_stmt_helper(compiler_t *comp, int n, mp_parse_node_t *n
// this pre-bit is of the form "a as b"
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)nodes[0];
compile_node(comp, pns->nodes[0]);
- EMIT_ARG(setup_with, l_end);
+ EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH);
c_assign(comp, pns->nodes[1], ASSIGN_STORE);
} else {
// this pre-bit is just an expression
compile_node(comp, nodes[0]);
- EMIT_ARG(setup_with, l_end);
+ EMIT_ARG(setup_block, l_end, MP_EMIT_SETUP_BLOCK_WITH);
EMIT(pop_top);
}
compile_increase_except_level(comp);
@@ -1703,7 +1696,7 @@ STATIC void compile_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
STATIC void compile_yield_from(compiler_t *comp) {
EMIT_ARG(get_iter, false);
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- EMIT(yield_from);
+ EMIT_ARG(yield, MP_EMIT_YIELD_FROM);
}
#if MICROPY_PY_ASYNC_AWAIT
@@ -1730,7 +1723,7 @@ STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns
EMIT_ARG(label_assign, continue_label);
- EMIT_ARG(setup_except, try_exception_label);
+ EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT);
compile_increase_except_level(comp);
compile_load_id(comp, context);
@@ -1801,7 +1794,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
compile_load_id(comp, context);
EMIT_ARG(load_method, MP_QSTR___aexit__, false);
- EMIT_ARG(setup_except, try_exception_label);
+ EMIT_ARG(setup_block, try_exception_label, MP_EMIT_SETUP_BLOCK_EXCEPT);
compile_increase_except_level(comp);
// compile additional pre-bits and the body
compile_async_with_stmt_helper(comp, n - 1, nodes + 1, body);
@@ -1815,7 +1808,7 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, int n, mp_parse_nod
// at this point the stack contains: ..., __aexit__, self, exc
EMIT(dup_top);
#if MICROPY_CPYTHON_COMPAT
- EMIT_ARG(load_attr, MP_QSTR___class__); // get type(exc)
+ EMIT_ARG(attr, MP_QSTR___class__, MP_EMIT_ATTR_LOAD); // get type(exc)
#else
compile_load_id(comp, MP_QSTR_type);
EMIT(rot_two);
@@ -1940,66 +1933,58 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
} else {
plain_assign:
- if (MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
- && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr)
- && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)
- && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 2
- && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) {
- // optimisation for a, b = c, d
- mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1];
- mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
- if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)
- || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) {
- // can't optimise when it's a star expression on the lhs
- goto no_optimisation;
- }
- compile_node(comp, pns10->nodes[0]); // rhs
- compile_node(comp, pns10->nodes[1]); // rhs
- EMIT(rot_two);
- c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store
- c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store
- } else if (MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
- && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr)
- && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)
- && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[1]) == 3
- && MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) {
- // optimisation for a, b, c = d, e, f
- mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns->nodes[1];
+ #if MICROPY_COMP_DOUBLE_TUPLE_ASSIGN
+ if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_testlist_star_expr)
+ && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)) {
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
- if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)
- || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)
- || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) {
- // can't optimise when it's a star expression on the lhs
- goto no_optimisation;
+ pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
+ uint32_t n_pns0 = MP_PARSE_NODE_STRUCT_NUM_NODES(pns0);
+ // Can only optimise a tuple-to-tuple assignment when all of the following hold:
+ // - equal number of items in LHS and RHS tuples
+ // - 2 or 3 items in the tuples
+ // - there are no star expressions in the LHS tuple
+ if (n_pns0 == MP_PARSE_NODE_STRUCT_NUM_NODES(pns1)
+ && (n_pns0 == 2
+ #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
+ || n_pns0 == 3
+ #endif
+ )
+ && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)
+ && !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)
+ #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
+ && (n_pns0 == 2 || !MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr))
+ #endif
+ ) {
+ // Optimisation for a, b = c, d or a, b, c = d, e, f
+ compile_node(comp, pns1->nodes[0]); // rhs
+ compile_node(comp, pns1->nodes[1]); // rhs
+ #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
+ if (n_pns0 == 3) {
+ compile_node(comp, pns1->nodes[2]); // rhs
+ EMIT(rot_three);
+ }
+ #endif
+ EMIT(rot_two);
+ c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store
+ c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store
+ #if MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
+ if (n_pns0 == 3) {
+ c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store
+ }
+ #endif
+ return;
}
- compile_node(comp, pns10->nodes[0]); // rhs
- compile_node(comp, pns10->nodes[1]); // rhs
- compile_node(comp, pns10->nodes[2]); // rhs
- EMIT(rot_three);
- EMIT(rot_two);
- c_assign(comp, pns0->nodes[0], ASSIGN_STORE); // lhs store
- c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store
- c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store
- } else {
- no_optimisation:
- compile_node(comp, pns->nodes[1]); // rhs
- c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store
}
+ #endif
+
+ compile_node(comp, pns->nodes[1]); // rhs
+ c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store
}
} else {
goto plain_assign;
}
}
-STATIC void c_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns, mp_binary_op_t binary_op) {
- int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
- compile_node(comp, pns->nodes[0]);
- for (int i = 1; i < num_nodes; i += 1) {
- compile_node(comp, pns->nodes[i]);
- EMIT_ARG(binary_op, binary_op);
- }
-}
-
STATIC void compile_test_if_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_test_if_else));
mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns->nodes[1];
@@ -2030,7 +2015,8 @@ STATIC void compile_lambdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_funcdef_lambdef(comp, this_scope, pns->nodes[0], PN_varargslist);
}
-STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, bool cond) {
+STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ bool cond = MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test;
uint l_end = comp_next_label(comp);
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (int i = 0; i < n; i += 1) {
@@ -2042,14 +2028,6 @@ STATIC void compile_or_and_test(compiler_t *comp, mp_parse_node_struct_t *pns, b
EMIT_ARG(label_assign, l_end);
}
-STATIC void compile_or_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
- compile_or_and_test(comp, pns, true);
-}
-
-STATIC void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) {
- compile_or_and_test(comp, pns, false);
-}
-
STATIC void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_node(comp, pns->nodes[0]);
EMIT_ARG(unary_op, MP_UNARY_OP_NOT);
@@ -2115,16 +2093,16 @@ STATIC void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_syntax_error(comp, (mp_parse_node_t)pns, "*x must be assignment target");
}
-STATIC void compile_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
- c_binary_op(comp, pns, MP_BINARY_OP_OR);
-}
-
-STATIC void compile_xor_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
- c_binary_op(comp, pns, MP_BINARY_OP_XOR);
-}
-
-STATIC void compile_and_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
- c_binary_op(comp, pns, MP_BINARY_OP_AND);
+STATIC void compile_binary_op(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_xor_expr - PN_expr == MP_BINARY_OP_XOR);
+ MP_STATIC_ASSERT(MP_BINARY_OP_OR + PN_and_expr - PN_expr == MP_BINARY_OP_AND);
+ mp_binary_op_t binary_op = MP_BINARY_OP_OR + MP_PARSE_NODE_STRUCT_KIND(pns) - PN_expr;
+ int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
+ compile_node(comp, pns->nodes[0]);
+ for (int i = 1; i < num_nodes; ++i) {
+ compile_node(comp, pns->nodes[i]);
+ EMIT_ARG(binary_op, binary_op);
+ }
}
STATIC void compile_term(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -2400,7 +2378,7 @@ STATIC void compile_atom_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) {
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// empty list
- EMIT_ARG(build_list, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[0];
if (MP_PARSE_NODE_IS_STRUCT(pns2->nodes[1])) {
@@ -2409,12 +2387,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
// list of one item, with trailing comma
assert(MP_PARSE_NODE_IS_NULL(pns3->nodes[0]));
compile_node(comp, pns2->nodes[0]);
- EMIT_ARG(build_list, 1);
+ EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_testlist_comp_3c) {
// list of many items
compile_node(comp, pns2->nodes[0]);
compile_generic_all_nodes(comp, pns3);
- EMIT_ARG(build_list, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3));
+ EMIT_ARG(build, 1 + MP_PARSE_NODE_STRUCT_NUM_NODES(pns3), MP_EMIT_BUILD_LIST);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns3) == PN_comp_for) {
// list comprehension
compile_comprehension(comp, pns2, SCOPE_LIST_COMP);
@@ -2427,12 +2405,12 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
list_with_2_items:
compile_node(comp, pns2->nodes[0]);
compile_node(comp, pns2->nodes[1]);
- EMIT_ARG(build_list, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_LIST);
}
} else {
// list with 1 item
compile_node(comp, pns->nodes[0]);
- EMIT_ARG(build_list, 1);
+ EMIT_ARG(build, 1, MP_EMIT_BUILD_LIST);
}
}
@@ -2440,12 +2418,12 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
mp_parse_node_t pn = pns->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) {
// empty dict
- EMIT_ARG(build_map, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) {
// dict with one element
- EMIT_ARG(build_map, 1);
+ EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP);
compile_node(comp, pn);
EMIT(store_map);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {
@@ -2462,7 +2440,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
bool is_dict;
if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) {
// a dictionary
- EMIT_ARG(build_map, 1 + n);
+ EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP);
compile_node(comp, pns->nodes[0]);
EMIT(store_map);
is_dict = true;
@@ -2502,7 +2480,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
#if MICROPY_PY_BUILTINS_SET
// if it's a set, build it
if (!is_dict) {
- EMIT_ARG(build_set, 1 + n);
+ EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_SET);
}
#endif
} else {
@@ -2525,7 +2503,7 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
set_with_one_element:
#if MICROPY_PY_BUILTINS_SET
compile_node(comp, pn);
- EMIT_ARG(build_set, 1);
+ EMIT_ARG(build, 1, MP_EMIT_BUILD_SET);
#else
assert(0);
#endif
@@ -2539,22 +2517,31 @@ STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns)
STATIC void compile_trailer_bracket(compiler_t *comp, mp_parse_node_struct_t *pns) {
// object who's index we want is on top of stack
compile_node(comp, pns->nodes[0]); // the index
- EMIT(load_subscr);
+ EMIT_ARG(subscr, MP_EMIT_SUBSCR_LOAD);
}
STATIC void compile_trailer_period(compiler_t *comp, mp_parse_node_struct_t *pns) {
// object who's attribute we want is on top of stack
- EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); // attribute to get
+ EMIT_ARG(attr, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]), MP_EMIT_ATTR_LOAD); // attribute to get
}
#if MICROPY_PY_BUILTINS_SLICE
-STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t *pns) {
+STATIC void compile_subscript(compiler_t *comp, mp_parse_node_struct_t *pns) {
+ if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_2) {
+ compile_node(comp, pns->nodes[0]); // start of slice
+ assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be
+ pns = (mp_parse_node_struct_t*)pns->nodes[1];
+ } else {
+ // pns is a PN_subscript_3, load None for start of slice
+ EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
+ }
+
assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3); // should always be
mp_parse_node_t pn = pns->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) {
// [?:]
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- EMIT_ARG(build_slice, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3c) {
@@ -2562,11 +2549,11 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t
pn = pns->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) {
// [?::]
- EMIT_ARG(build_slice, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);
} else {
// [?::x]
compile_node(comp, pn);
- EMIT_ARG(build_slice, 3);
+ EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE);
}
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_subscript_3d) {
compile_node(comp, pns->nodes[0]);
@@ -2575,34 +2562,23 @@ STATIC void compile_subscript_3_helper(compiler_t *comp, mp_parse_node_struct_t
assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_sliceop); // should always be
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
// [?:x:]
- EMIT_ARG(build_slice, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);
} else {
// [?:x:x]
compile_node(comp, pns->nodes[0]);
- EMIT_ARG(build_slice, 3);
+ EMIT_ARG(build, 3, MP_EMIT_BUILD_SLICE);
}
} else {
// [?:x]
compile_node(comp, pn);
- EMIT_ARG(build_slice, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);
}
} else {
// [?:x]
compile_node(comp, pn);
- EMIT_ARG(build_slice, 2);
+ EMIT_ARG(build, 2, MP_EMIT_BUILD_SLICE);
}
}
-
-STATIC void compile_subscript_2(compiler_t *comp, mp_parse_node_struct_t *pns) {
- compile_node(comp, pns->nodes[0]); // start of slice
- assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should always be
- compile_subscript_3_helper(comp, (mp_parse_node_struct_t*)pns->nodes[1]);
-}
-
-STATIC void compile_subscript_3(compiler_t *comp, mp_parse_node_struct_t *pns) {
- EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- compile_subscript_3_helper(comp, pns);
-}
#endif // MICROPY_PY_BUILTINS_SLICE
STATIC void compile_dictorsetmaker_item(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -2624,14 +2600,14 @@ STATIC void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
- EMIT(yield_value);
+ EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);
} else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_yield_arg_from)) {
pns = (mp_parse_node_struct_t*)pns->nodes[0];
compile_node(comp, pns->nodes[0]);
compile_yield_from(comp);
} else {
compile_node(comp, pns->nodes[0]);
- EMIT(yield_value);
+ EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);
}
}
@@ -2865,7 +2841,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_struct_t *pn
// no more nested if/for; compile inner expression
compile_node(comp, pn_inner_expr);
if (comp->scope_cur->kind == SCOPE_GEN_EXPR) {
- EMIT(yield_value);
+ EMIT_ARG(yield, MP_EMIT_YIELD_VALUE);
EMIT(pop_top);
} else {
EMIT_ARG(store_comp, comp->scope_cur->kind, 4 * for_depth + 5);
@@ -3043,19 +3019,19 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
}
if (scope->kind == SCOPE_LIST_COMP) {
- EMIT_ARG(build_list, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_LIST);
} else if (scope->kind == SCOPE_DICT_COMP) {
- EMIT_ARG(build_map, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);
#if MICROPY_PY_BUILTINS_SET
} else if (scope->kind == SCOPE_SET_COMP) {
- EMIT_ARG(build_set, 0);
+ EMIT_ARG(build, 0, MP_EMIT_BUILD_SET);
#endif
}
// There are 4 slots on the stack for the iterator, and the first one is
// NULL to indicate that the second one points to the iterator object.
if (scope->kind == SCOPE_GEN_EXPR) {
- // TODO static assert that MP_OBJ_ITER_BUF_NSLOTS == 4
+ MP_STATIC_ASSERT(MP_OBJ_ITER_BUF_NSLOTS == 4);
EMIT(load_null);
compile_load_id(comp, qstr_arg);
EMIT(load_null);
diff --git a/py/emit.h b/py/emit.h
index 270a40633..aa98efa77 100644
--- a/py/emit.h
+++ b/py/emit.h
@@ -55,13 +55,50 @@ typedef enum {
#define MP_EMIT_NATIVE_TYPE_RETURN (1)
#define MP_EMIT_NATIVE_TYPE_ARG (2)
+// Kind for emit_id_ops->local()
+#define MP_EMIT_IDOP_LOCAL_FAST (0)
+#define MP_EMIT_IDOP_LOCAL_DEREF (1)
+
+// Kind for emit_id_ops->global()
+#define MP_EMIT_IDOP_GLOBAL_NAME (0)
+#define MP_EMIT_IDOP_GLOBAL_GLOBAL (1)
+
+// Kind for emit->import()
+#define MP_EMIT_IMPORT_NAME (0)
+#define MP_EMIT_IMPORT_FROM (1)
+#define MP_EMIT_IMPORT_STAR (2)
+
+// Kind for emit->subscr()
+#define MP_EMIT_SUBSCR_LOAD (0)
+#define MP_EMIT_SUBSCR_STORE (1)
+#define MP_EMIT_SUBSCR_DELETE (2)
+
+// Kind for emit->attr()
+#define MP_EMIT_ATTR_LOAD (0)
+#define MP_EMIT_ATTR_STORE (1)
+#define MP_EMIT_ATTR_DELETE (2)
+
+// Kind for emit->setup_block()
+#define MP_EMIT_SETUP_BLOCK_WITH (0)
+#define MP_EMIT_SETUP_BLOCK_EXCEPT (2)
+#define MP_EMIT_SETUP_BLOCK_FINALLY (3)
+
+// Kind for emit->build()
+#define MP_EMIT_BUILD_TUPLE (0)
+#define MP_EMIT_BUILD_LIST (1)
+#define MP_EMIT_BUILD_MAP (3)
+#define MP_EMIT_BUILD_SET (6)
+#define MP_EMIT_BUILD_SLICE (8)
+
+// Kind for emit->yield()
+#define MP_EMIT_YIELD_VALUE (0)
+#define MP_EMIT_YIELD_FROM (1)
+
typedef struct _emit_t emit_t;
typedef struct _mp_emit_method_table_id_ops_t {
- void (*fast)(emit_t *emit, qstr qst, mp_uint_t local_num);
- void (*deref)(emit_t *emit, qstr qst, mp_uint_t local_num);
- void (*name)(emit_t *emit, qstr qst);
- void (*global)(emit_t *emit, qstr qst);
+ void (*local)(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);
+ void (*global)(emit_t *emit, qstr qst, int kind);
} mp_emit_method_table_id_ops_t;
typedef struct _emit_method_table_t {
@@ -77,22 +114,16 @@ typedef struct _emit_method_table_t {
mp_emit_method_table_id_ops_t delete_id;
void (*label_assign)(emit_t *emit, mp_uint_t l);
- void (*import_name)(emit_t *emit, qstr qst);
- void (*import_from)(emit_t *emit, qstr qst);
- void (*import_star)(emit_t *emit);
+ void (*import)(emit_t *emit, qstr qst, int kind);
void (*load_const_tok)(emit_t *emit, mp_token_kind_t tok);
void (*load_const_small_int)(emit_t *emit, mp_int_t arg);
void (*load_const_str)(emit_t *emit, qstr qst);
void (*load_const_obj)(emit_t *emit, mp_obj_t obj);
void (*load_null)(emit_t *emit);
- void (*load_attr)(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_subscr)(emit_t *emit);
- void (*store_attr)(emit_t *emit, qstr qst);
- void (*store_subscr)(emit_t *emit);
- void (*delete_attr)(emit_t *emit, qstr qst);
- void (*delete_subscr)(emit_t *emit);
+ void (*subscr)(emit_t *emit, int kind);
+ void (*attr)(emit_t *emit, qstr qst, int kind);
void (*dup_top)(emit_t *emit);
void (*dup_top_two)(emit_t *emit);
void (*pop_top)(emit_t *emit);
@@ -101,12 +132,9 @@ typedef struct _emit_method_table_t {
void (*jump)(emit_t *emit, mp_uint_t label);
void (*pop_jump_if)(emit_t *emit, bool cond, mp_uint_t label);
void (*jump_if_or_pop)(emit_t *emit, bool cond, mp_uint_t label);
- void (*break_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
- void (*continue_loop)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
- void (*setup_with)(emit_t *emit, mp_uint_t label);
+ void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
+ void (*setup_block)(emit_t *emit, mp_uint_t label, int kind);
void (*with_cleanup)(emit_t *emit, mp_uint_t label);
- void (*setup_except)(emit_t *emit, mp_uint_t label);
- void (*setup_finally)(emit_t *emit, mp_uint_t label);
void (*end_finally)(emit_t *emit);
void (*get_iter)(emit_t *emit, bool use_stack);
void (*for_iter)(emit_t *emit, mp_uint_t label);
@@ -115,16 +143,8 @@ typedef struct _emit_method_table_t {
void (*pop_except)(emit_t *emit);
void (*unary_op)(emit_t *emit, mp_unary_op_t op);
void (*binary_op)(emit_t *emit, mp_binary_op_t op);
- void (*build_tuple)(emit_t *emit, mp_uint_t n_args);
- void (*build_list)(emit_t *emit, mp_uint_t n_args);
- void (*build_map)(emit_t *emit, mp_uint_t n_args);
+ void (*build)(emit_t *emit, mp_uint_t n_args, int kind);
void (*store_map)(emit_t *emit);
- #if MICROPY_PY_BUILTINS_SET
- void (*build_set)(emit_t *emit, mp_uint_t n_args);
- #endif
- #if MICROPY_PY_BUILTINS_SLICE
- void (*build_slice)(emit_t *emit, mp_uint_t n_args);
- #endif
void (*store_comp)(emit_t *emit, scope_kind_t kind, mp_uint_t set_stack_index);
void (*unpack_sequence)(emit_t *emit, mp_uint_t n_args);
void (*unpack_ex)(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right);
@@ -134,8 +154,7 @@ typedef struct _emit_method_table_t {
void (*call_method)(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);
void (*return_value)(emit_t *emit);
void (*raise_varargs)(emit_t *emit, mp_uint_t n_args);
- void (*yield_value)(emit_t *emit);
- void (*yield_from)(emit_t *emit);
+ void (*yield)(emit_t *emit, int kind);
// these methods are used to control entry to/exit from an exception handler
// they may or may not emit code
@@ -180,36 +199,24 @@ bool mp_emit_bc_last_emit_was_return_value(emit_t *emit);
void mp_emit_bc_adjust_stack_size(emit_t *emit, mp_int_t delta);
void mp_emit_bc_set_source_line(emit_t *emit, mp_uint_t line);
-void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_load_name(emit_t *emit, qstr qst);
-void mp_emit_bc_load_global(emit_t *emit, qstr qst);
-void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_store_name(emit_t *emit, qstr qst);
-void mp_emit_bc_store_global(emit_t *emit, qstr qst);
-void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num);
-void mp_emit_bc_delete_name(emit_t *emit, qstr qst);
-void mp_emit_bc_delete_global(emit_t *emit, qstr qst);
+void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);
+void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind);
+void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);
+void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind);
+void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind);
+void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind);
void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l);
-void mp_emit_bc_import_name(emit_t *emit, qstr qst);
-void mp_emit_bc_import_from(emit_t *emit, qstr qst);
-void mp_emit_bc_import_star(emit_t *emit);
+void mp_emit_bc_import(emit_t *emit, qstr qst, int kind);
void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok);
void mp_emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg);
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_null(emit_t *emit);
-void mp_emit_bc_load_attr(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_subscr(emit_t *emit);
-void mp_emit_bc_store_attr(emit_t *emit, qstr qst);
-void mp_emit_bc_store_subscr(emit_t *emit);
-void mp_emit_bc_delete_attr(emit_t *emit, qstr qst);
-void mp_emit_bc_delete_subscr(emit_t *emit);
+void mp_emit_bc_subscr(emit_t *emit, int kind);
+void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind);
void mp_emit_bc_dup_top(emit_t *emit);
void mp_emit_bc_dup_top_two(emit_t *emit);
void mp_emit_bc_pop_top(emit_t *emit);
@@ -219,12 +226,8 @@ void mp_emit_bc_jump(emit_t *emit, mp_uint_t label);
void mp_emit_bc_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label);
void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label);
void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth);
-#define mp_emit_bc_break_loop mp_emit_bc_unwind_jump
-#define mp_emit_bc_continue_loop mp_emit_bc_unwind_jump
-void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label);
+void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind);
void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label);
-void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label);
-void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label);
void mp_emit_bc_end_finally(emit_t *emit);
void mp_emit_bc_get_iter(emit_t *emit, bool use_stack);
void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label);
@@ -233,16 +236,8 @@ void mp_emit_bc_pop_block(emit_t *emit);
void mp_emit_bc_pop_except(emit_t *emit);
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op);
void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op);
-void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args);
-void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args);
-void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args);
+void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind);
void mp_emit_bc_store_map(emit_t *emit);
-#if MICROPY_PY_BUILTINS_SET
-void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args);
-#endif
-#if MICROPY_PY_BUILTINS_SLICE
-void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args);
-#endif
void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t list_stack_index);
void mp_emit_bc_unpack_sequence(emit_t *emit, mp_uint_t n_args);
void mp_emit_bc_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right);
@@ -252,8 +247,7 @@ void mp_emit_bc_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_
void mp_emit_bc_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags);
void mp_emit_bc_return_value(emit_t *emit);
void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args);
-void mp_emit_bc_yield_value(emit_t *emit);
-void mp_emit_bc_yield_from(emit_t *emit);
+void mp_emit_bc_yield(emit_t *emit, int kind);
void mp_emit_bc_start_except_handler(emit_t *emit);
void mp_emit_bc_end_except_handler(emit_t *emit);
diff --git a/py/emitbc.c b/py/emitbc.c
index 3f4dfc178..f3951e9cb 100644
--- a/py/emitbc.c
+++ b/py/emitbc.c
@@ -313,9 +313,12 @@ void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
emit->scope = scope;
emit->last_source_line_offset = 0;
emit->last_source_line = 1;
- if (pass < MP_PASS_EMIT) {
+ #ifndef NDEBUG
+ // With debugging enabled labels are checked for unique assignment
+ if (pass < MP_PASS_EMIT && emit->label_offsets != NULL) {
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));
}
+ #endif
emit->bytecode_offset = 0;
emit->code_info_offset = 0;
@@ -434,7 +437,9 @@ void mp_emit_bc_end_pass(emit_t *emit) {
} else if (emit->pass == MP_PASS_EMIT) {
mp_emit_glue_assign_bytecode(emit->scope->raw_code, emit->code_base,
+ #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
emit->code_info_size + emit->bytecode_size,
+ #endif
emit->const_table,
#if MICROPY_PERSISTENT_CODE_SAVE
emit->ct_cur_obj, emit->ct_cur_raw_code,
@@ -495,24 +500,23 @@ void mp_emit_bc_label_assign(emit_t *emit, mp_uint_t l) {
emit->label_offsets[l] = emit->bytecode_offset;
} else {
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
- //printf("l%d: (at %d vs %d)\n", l, emit->bytecode_offset, emit->label_offsets[l]);
assert(emit->label_offsets[l] == emit->bytecode_offset);
}
}
-void mp_emit_bc_import_name(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME, qst);
-}
-
-void mp_emit_bc_import_from(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, 1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_FROM, qst);
-}
-
-void mp_emit_bc_import_star(emit_t *emit) {
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR);
+void mp_emit_bc_import(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_NAME == MP_BC_IMPORT_NAME);
+ MP_STATIC_ASSERT(MP_BC_IMPORT_NAME + MP_EMIT_IMPORT_FROM == MP_BC_IMPORT_FROM);
+ if (kind == MP_EMIT_IMPORT_FROM) {
+ emit_bc_pre(emit, 1);
+ } else {
+ emit_bc_pre(emit, -1);
+ }
+ if (kind == MP_EMIT_IMPORT_STAR) {
+ emit_write_bytecode_byte(emit, MP_BC_IMPORT_STAR);
+ } else {
+ emit_write_bytecode_byte_qstr(emit, MP_BC_IMPORT_NAME + kind, qst);
+ }
}
void mp_emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
@@ -552,43 +556,24 @@ void mp_emit_bc_load_null(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_NULL);
}
-void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
+void mp_emit_bc_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_LOAD_FAST_N);
+ MP_STATIC_ASSERT(MP_BC_LOAD_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_LOAD_DEREF);
(void)qst;
emit_bc_pre(emit, 1);
- if (local_num <= 15) {
+ if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num);
} else {
- emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num);
- }
-}
-
-void mp_emit_bc_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
- (void)qst;
- emit_bc_pre(emit, 1);
- emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_DEREF, local_num);
-}
-
-void mp_emit_bc_load_name(emit_t *emit, qstr qst) {
- (void)qst;
- emit_bc_pre(emit, 1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME, qst);
- if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
- emit_write_bytecode_byte(emit, 0);
+ emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N + kind, local_num);
}
}
-void mp_emit_bc_load_global(emit_t *emit, qstr qst) {
+void mp_emit_bc_load_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_LOAD_NAME);
+ MP_STATIC_ASSERT(MP_BC_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_LOAD_GLOBAL);
(void)qst;
emit_bc_pre(emit, 1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_GLOBAL, qst);
- if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
- emit_write_bytecode_byte(emit, 0);
- }
-}
-
-void mp_emit_bc_load_attr(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, 0);
- emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
+ emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_NAME + kind, qst);
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
emit_write_bytecode_byte(emit, 0);
}
@@ -604,80 +589,68 @@ void mp_emit_bc_load_build_class(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_LOAD_BUILD_CLASS);
}
-void mp_emit_bc_load_subscr(emit_t *emit) {
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR);
-}
-
-void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
- (void)qst;
- emit_bc_pre(emit, -1);
- if (local_num <= 15) {
- emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
+void mp_emit_bc_subscr(emit_t *emit, int kind) {
+ if (kind == MP_EMIT_SUBSCR_LOAD) {
+ emit_bc_pre(emit, -1);
+ emit_write_bytecode_byte(emit, MP_BC_LOAD_SUBSCR);
} else {
- emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num);
+ if (kind == MP_EMIT_SUBSCR_DELETE) {
+ mp_emit_bc_load_null(emit);
+ mp_emit_bc_rot_three(emit);
+ }
+ emit_bc_pre(emit, -3);
+ emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR);
}
}
-void mp_emit_bc_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
- (void)qst;
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte_uint(emit, MP_BC_STORE_DEREF, local_num);
-}
-
-void mp_emit_bc_store_name(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME, qst);
-}
-
-void mp_emit_bc_store_global(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, -1);
- emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_GLOBAL, qst);
-}
-
-void mp_emit_bc_store_attr(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, -2);
- emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
+void mp_emit_bc_attr(emit_t *emit, qstr qst, int kind) {
+ if (kind == MP_EMIT_ATTR_LOAD) {
+ emit_bc_pre(emit, 0);
+ emit_write_bytecode_byte_qstr(emit, MP_BC_LOAD_ATTR, qst);
+ } else {
+ if (kind == MP_EMIT_ATTR_DELETE) {
+ mp_emit_bc_load_null(emit);
+ mp_emit_bc_rot_two(emit);
+ }
+ emit_bc_pre(emit, -2);
+ emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_ATTR, qst);
+ }
if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE_DYNAMIC) {
emit_write_bytecode_byte(emit, 0);
}
}
-void mp_emit_bc_store_subscr(emit_t *emit) {
- emit_bc_pre(emit, -3);
- emit_write_bytecode_byte(emit, MP_BC_STORE_SUBSCR);
-}
-
-void mp_emit_bc_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
+void mp_emit_bc_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_STORE_FAST_N);
+ MP_STATIC_ASSERT(MP_BC_STORE_FAST_N + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_STORE_DEREF);
(void)qst;
- emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST, local_num);
+ emit_bc_pre(emit, -1);
+ if (kind == MP_EMIT_IDOP_LOCAL_FAST && local_num <= 15) {
+ emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
+ } else {
+ emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N + kind, local_num);
+ }
}
-void mp_emit_bc_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
- (void)qst;
- emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_DEREF, local_num);
+void mp_emit_bc_store_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_STORE_NAME);
+ MP_STATIC_ASSERT(MP_BC_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_STORE_GLOBAL);
+ emit_bc_pre(emit, -1);
+ emit_write_bytecode_byte_qstr(emit, MP_BC_STORE_NAME + kind, qst);
}
-void mp_emit_bc_delete_name(emit_t *emit, qstr qst) {
- emit_bc_pre(emit, 0);
- emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME, qst);
+void mp_emit_bc_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_FAST == MP_BC_DELETE_FAST);
+ MP_STATIC_ASSERT(MP_BC_DELETE_FAST + MP_EMIT_IDOP_LOCAL_DEREF == MP_BC_DELETE_DEREF);
+ (void)qst;
+ emit_write_bytecode_byte_uint(emit, MP_BC_DELETE_FAST + kind, local_num);
}
-void mp_emit_bc_delete_global(emit_t *emit, qstr qst) {
+void mp_emit_bc_delete_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_BC_DELETE_NAME);
+ MP_STATIC_ASSERT(MP_BC_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_BC_DELETE_GLOBAL);
emit_bc_pre(emit, 0);
- emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_GLOBAL, qst);
-}
-
-void mp_emit_bc_delete_attr(emit_t *emit, qstr qst) {
- mp_emit_bc_load_null(emit);
- mp_emit_bc_rot_two(emit);
- mp_emit_bc_store_attr(emit, qst);
-}
-
-void mp_emit_bc_delete_subscr(emit_t *emit) {
- mp_emit_bc_load_null(emit);
- mp_emit_bc_rot_three(emit);
- mp_emit_bc_store_subscr(emit);
+ emit_write_bytecode_byte_qstr(emit, MP_BC_DELETE_NAME + kind, qst);
}
void mp_emit_bc_dup_top(emit_t *emit) {
@@ -746,11 +719,18 @@ void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_dept
}
}
-void mp_emit_bc_setup_with(emit_t *emit, mp_uint_t label) {
+void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind) {
+ MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_WITH == MP_BC_SETUP_WITH);
+ MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_EXCEPT == MP_BC_SETUP_EXCEPT);
+ MP_STATIC_ASSERT(MP_BC_SETUP_WITH + MP_EMIT_SETUP_BLOCK_FINALLY == MP_BC_SETUP_FINALLY);
+ if (kind == MP_EMIT_SETUP_BLOCK_WITH) {
// The SETUP_WITH opcode pops ctx_mgr from the top of the stack
// and then pushes 3 entries: __exit__, ctx_mgr, as_value.
- emit_bc_pre(emit, 2);
- emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH, label);
+ emit_bc_pre(emit, 2);
+ } else {
+ emit_bc_pre(emit, 0);
+ }
+ emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_WITH + kind, label);
}
void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
@@ -759,17 +739,7 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) {
mp_emit_bc_label_assign(emit, label);
emit_bc_pre(emit, 2); // ensure we have enough stack space to call the __exit__ method
emit_write_bytecode_byte(emit, MP_BC_WITH_CLEANUP);
- emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_with
-}
-
-void mp_emit_bc_setup_except(emit_t *emit, mp_uint_t label) {
- emit_bc_pre(emit, 0);
- emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_EXCEPT, label);
-}
-
-void mp_emit_bc_setup_finally(emit_t *emit, mp_uint_t label) {
- emit_bc_pre(emit, 0);
- emit_write_bytecode_byte_unsigned_label(emit, MP_BC_SETUP_FINALLY, label);
+ emit_bc_pre(emit, -4); // cancel the 2 above, plus the 2 from mp_emit_bc_setup_block(MP_EMIT_SETUP_BLOCK_WITH)
}
void mp_emit_bc_end_finally(emit_t *emit) {
@@ -823,19 +793,18 @@ void mp_emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
}
}
-void mp_emit_bc_build_tuple(emit_t *emit, mp_uint_t n_args) {
- emit_bc_pre(emit, 1 - n_args);
- emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE, n_args);
-}
-
-void mp_emit_bc_build_list(emit_t *emit, mp_uint_t n_args) {
- emit_bc_pre(emit, 1 - n_args);
- emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_LIST, n_args);
-}
-
-void mp_emit_bc_build_map(emit_t *emit, mp_uint_t n_args) {
- emit_bc_pre(emit, 1);
- emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_MAP, n_args);
+void mp_emit_bc_build(emit_t *emit, mp_uint_t n_args, int kind) {
+ MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_BC_BUILD_TUPLE);
+ MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_BC_BUILD_LIST);
+ MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_BC_BUILD_MAP);
+ MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_BC_BUILD_SET);
+ MP_STATIC_ASSERT(MP_BC_BUILD_TUPLE + MP_EMIT_BUILD_SLICE == MP_BC_BUILD_SLICE);
+ if (kind == MP_EMIT_BUILD_MAP) {
+ emit_bc_pre(emit, 1);
+ } else {
+ emit_bc_pre(emit, 1 - n_args);
+ }
+ emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_TUPLE + kind, n_args);
}
void mp_emit_bc_store_map(emit_t *emit) {
@@ -843,20 +812,6 @@ void mp_emit_bc_store_map(emit_t *emit) {
emit_write_bytecode_byte(emit, MP_BC_STORE_MAP);
}
-#if MICROPY_PY_BUILTINS_SET
-void mp_emit_bc_build_set(emit_t *emit, mp_uint_t n_args) {
- emit_bc_pre(emit, 1 - n_args);
- emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SET, n_args);
-}
-#endif
-
-#if MICROPY_PY_BUILTINS_SLICE
-void mp_emit_bc_build_slice(emit_t *emit, mp_uint_t n_args) {
- emit_bc_pre(emit, 1 - n_args);
- emit_write_bytecode_byte_uint(emit, MP_BC_BUILD_SLICE, n_args);
-}
-#endif
-
void mp_emit_bc_store_comp(emit_t *emit, scope_kind_t kind, mp_uint_t collection_stack_index) {
int t;
int n;
@@ -938,16 +893,11 @@ void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) {
emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args);
}
-void mp_emit_bc_yield_value(emit_t *emit) {
- emit_bc_pre(emit, 0);
- emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
- emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE);
-}
-
-void mp_emit_bc_yield_from(emit_t *emit) {
- emit_bc_pre(emit, -1);
+void mp_emit_bc_yield(emit_t *emit, int kind) {
+ MP_STATIC_ASSERT(MP_BC_YIELD_VALUE + 1 == MP_BC_YIELD_FROM);
+ emit_bc_pre(emit, -kind);
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
- emit_write_bytecode_byte(emit, MP_BC_YIELD_FROM);
+ emit_write_bytecode_byte(emit, MP_BC_YIELD_VALUE + kind);
}
void mp_emit_bc_start_except_handler(emit_t *emit) {
@@ -968,41 +918,29 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_set_source_line,
{
- mp_emit_bc_load_fast,
- mp_emit_bc_load_deref,
- mp_emit_bc_load_name,
+ mp_emit_bc_load_local,
mp_emit_bc_load_global,
},
{
- mp_emit_bc_store_fast,
- mp_emit_bc_store_deref,
- mp_emit_bc_store_name,
+ mp_emit_bc_store_local,
mp_emit_bc_store_global,
},
{
- mp_emit_bc_delete_fast,
- mp_emit_bc_delete_deref,
- mp_emit_bc_delete_name,
+ mp_emit_bc_delete_local,
mp_emit_bc_delete_global,
},
mp_emit_bc_label_assign,
- mp_emit_bc_import_name,
- mp_emit_bc_import_from,
- mp_emit_bc_import_star,
+ mp_emit_bc_import,
mp_emit_bc_load_const_tok,
mp_emit_bc_load_const_small_int,
mp_emit_bc_load_const_str,
mp_emit_bc_load_const_obj,
mp_emit_bc_load_null,
- mp_emit_bc_load_attr,
mp_emit_bc_load_method,
mp_emit_bc_load_build_class,
- mp_emit_bc_load_subscr,
- mp_emit_bc_store_attr,
- mp_emit_bc_store_subscr,
- mp_emit_bc_delete_attr,
- mp_emit_bc_delete_subscr,
+ mp_emit_bc_subscr,
+ mp_emit_bc_attr,
mp_emit_bc_dup_top,
mp_emit_bc_dup_top_two,
mp_emit_bc_pop_top,
@@ -1012,11 +950,8 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_pop_jump_if,
mp_emit_bc_jump_if_or_pop,
mp_emit_bc_unwind_jump,
- mp_emit_bc_unwind_jump,
- mp_emit_bc_setup_with,
+ mp_emit_bc_setup_block,
mp_emit_bc_with_cleanup,
- mp_emit_bc_setup_except,
- mp_emit_bc_setup_finally,
mp_emit_bc_end_finally,
mp_emit_bc_get_iter,
mp_emit_bc_for_iter,
@@ -1025,16 +960,8 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_pop_except,
mp_emit_bc_unary_op,
mp_emit_bc_binary_op,
- mp_emit_bc_build_tuple,
- mp_emit_bc_build_list,
- mp_emit_bc_build_map,
+ mp_emit_bc_build,
mp_emit_bc_store_map,
- #if MICROPY_PY_BUILTINS_SET
- mp_emit_bc_build_set,
- #endif
- #if MICROPY_PY_BUILTINS_SLICE
- mp_emit_bc_build_slice,
- #endif
mp_emit_bc_store_comp,
mp_emit_bc_unpack_sequence,
mp_emit_bc_unpack_ex,
@@ -1044,31 +971,24 @@ const emit_method_table_t emit_bc_method_table = {
mp_emit_bc_call_method,
mp_emit_bc_return_value,
mp_emit_bc_raise_varargs,
- mp_emit_bc_yield_value,
- mp_emit_bc_yield_from,
+ mp_emit_bc_yield,
mp_emit_bc_start_except_handler,
mp_emit_bc_end_except_handler,
};
#else
const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops = {
- mp_emit_bc_load_fast,
- mp_emit_bc_load_deref,
- mp_emit_bc_load_name,
+ mp_emit_bc_load_local,
mp_emit_bc_load_global,
};
const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops = {
- mp_emit_bc_store_fast,
- mp_emit_bc_store_deref,
- mp_emit_bc_store_name,
+ mp_emit_bc_store_local,
mp_emit_bc_store_global,
};
const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = {
- mp_emit_bc_delete_fast,
- mp_emit_bc_delete_deref,
- mp_emit_bc_delete_name,
+ mp_emit_bc_delete_local,
mp_emit_bc_delete_global,
};
#endif
diff --git a/py/emitcommon.c b/py/emitcommon.c
index 07b1dbb4c..89cc2c959 100644
--- a/py/emitcommon.c
+++ b/py/emitcommon.c
@@ -63,14 +63,14 @@ void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emi
// call the emit backend with the correct code
if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
- emit_method_table->name(emit, qst);
+ emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_NAME);
} else if (id->kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
- emit_method_table->global(emit, qst);
+ emit_method_table->global(emit, qst, MP_EMIT_IDOP_GLOBAL_GLOBAL);
} else if (id->kind == ID_INFO_KIND_LOCAL) {
- emit_method_table->fast(emit, qst, id->local_num);
+ emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_FAST);
} else {
assert(id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE);
- emit_method_table->deref(emit, qst, id->local_num);
+ emit_method_table->local(emit, qst, id->local_num, MP_EMIT_IDOP_LOCAL_DEREF);
}
}
diff --git a/py/emitglue.c b/py/emitglue.c
index d2add988f..74bf8ddca 100644
--- a/py/emitglue.c
+++ b/py/emitglue.c
@@ -55,7 +55,10 @@ mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
return rc;
}
-void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len,
+void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
+ #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
+ size_t len,
+ #endif
const mp_uint_t *const_table,
#if MICROPY_PERSISTENT_CODE_SAVE
uint16_t n_obj, uint16_t n_raw_code,
diff --git a/py/emitglue.h b/py/emitglue.h
index 43930333d..0830a0d5c 100644
--- a/py/emitglue.h
+++ b/py/emitglue.h
@@ -40,7 +40,7 @@ typedef enum {
} mp_raw_code_kind_t;
typedef struct _mp_raw_code_t {
- mp_raw_code_kind_t kind : 3;
+ mp_uint_t kind : 3; // of type mp_raw_code_kind_t
mp_uint_t scope_flags : 7;
mp_uint_t n_pos_args : 11;
union {
@@ -63,7 +63,10 @@ typedef struct _mp_raw_code_t {
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
-void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code, mp_uint_t len,
+void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, const byte *code,
+ #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
+ size_t len,
+ #endif
const mp_uint_t *const_table,
#if MICROPY_PERSISTENT_CODE_SAVE
uint16_t n_obj, uint16_t n_raw_code,
diff --git a/py/emitnarm.c b/py/emitnarm.c
new file mode 100644
index 000000000..1b585f821
--- /dev/null
+++ b/py/emitnarm.c
@@ -0,0 +1,15 @@
+// ARM specific stuff
+
+#include "py/mpconfig.h"
+
+#if MICROPY_EMIT_ARM
+
+// This is defined so that the assembler exports generic assembler API macros
+#define GENERIC_ASM_API (1)
+#include "py/asmarm.h"
+
+#define N_ARM (1)
+#define EXPORT_FUN(name) emit_native_arm_##name
+#include "py/emitnative.c"
+
+#endif
diff --git a/py/emitnative.c b/py/emitnative.c
index 8e97dda11..ad8f04aac 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -57,102 +57,14 @@
#endif
// wrapper around everything in this file
-#if (MICROPY_EMIT_X64 && N_X64) \
- || (MICROPY_EMIT_X86 && N_X86) \
- || (MICROPY_EMIT_THUMB && N_THUMB) \
- || (MICROPY_EMIT_ARM && N_ARM) \
- || (MICROPY_EMIT_XTENSA && N_XTENSA) \
-
-// this is defined so that the assembler exports generic assembler API macros
-#define GENERIC_ASM_API (1)
-
-#if N_X64
-
-// x64 specific stuff
-#include "py/asmx64.h"
-#define EXPORT_FUN(name) emit_native_x64_##name
-
-#elif N_X86
-
-// x86 specific stuff
-
-STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
- [MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
- [MP_F_CONVERT_NATIVE_TO_OBJ] = 2,
- [MP_F_LOAD_NAME] = 1,
- [MP_F_LOAD_GLOBAL] = 1,
- [MP_F_LOAD_BUILD_CLASS] = 0,
- [MP_F_LOAD_ATTR] = 2,
- [MP_F_LOAD_METHOD] = 3,
- [MP_F_LOAD_SUPER_METHOD] = 2,
- [MP_F_STORE_NAME] = 2,
- [MP_F_STORE_GLOBAL] = 2,
- [MP_F_STORE_ATTR] = 3,
- [MP_F_OBJ_SUBSCR] = 3,
- [MP_F_OBJ_IS_TRUE] = 1,
- [MP_F_UNARY_OP] = 2,
- [MP_F_BINARY_OP] = 3,
- [MP_F_BUILD_TUPLE] = 2,
- [MP_F_BUILD_LIST] = 2,
- [MP_F_LIST_APPEND] = 2,
- [MP_F_BUILD_MAP] = 1,
- [MP_F_STORE_MAP] = 3,
-#if MICROPY_PY_BUILTINS_SET
- [MP_F_BUILD_SET] = 2,
- [MP_F_STORE_SET] = 2,
-#endif
- [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,
- [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,
- [MP_F_CALL_METHOD_N_KW] = 3,
- [MP_F_CALL_METHOD_N_KW_VAR] = 3,
- [MP_F_NATIVE_GETITER] = 2,
- [MP_F_NATIVE_ITERNEXT] = 1,
- [MP_F_NLR_PUSH] = 1,
- [MP_F_NLR_POP] = 0,
- [MP_F_NATIVE_RAISE] = 1,
- [MP_F_IMPORT_NAME] = 3,
- [MP_F_IMPORT_FROM] = 2,
- [MP_F_IMPORT_ALL] = 1,
-#if MICROPY_PY_BUILTINS_SLICE
- [MP_F_NEW_SLICE] = 3,
-#endif
- [MP_F_UNPACK_SEQUENCE] = 3,
- [MP_F_UNPACK_EX] = 3,
- [MP_F_DELETE_NAME] = 1,
- [MP_F_DELETE_GLOBAL] = 1,
- [MP_F_NEW_CELL] = 1,
- [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
- [MP_F_SETUP_CODE_STATE] = 5,
- [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,
- [MP_F_SMALL_INT_MODULO] = 2,
-};
-
-#include "py/asmx86.h"
-#define EXPORT_FUN(name) emit_native_x86_##name
-
-#elif N_THUMB
-
-// thumb specific stuff
-#include "py/asmthumb.h"
-#define EXPORT_FUN(name) emit_native_thumb_##name
-
-#elif N_ARM
-
-// ARM specific stuff
-#include "py/asmarm.h"
-#define EXPORT_FUN(name) emit_native_arm_##name
-
-#elif N_XTENSA
-
-// Xtensa specific stuff
-#include "py/asmxtensa.h"
-#define EXPORT_FUN(name) emit_native_xtensa_##name
-
-#else
-
-#error unknown native emitter
+#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA
-#endif
+// define additional generic helper macros
+#define ASM_MOV_LOCAL_IMM_VIA(as, local_num, imm, reg_temp) \
+ do { \
+ ASM_MOV_REG_IMM((as), (reg_temp), (imm)); \
+ ASM_MOV_LOCAL_REG((as), (local_num), (reg_temp)); \
+ } while (false)
#define EMIT_NATIVE_VIPER_TYPE_ERROR(emit, ...) do { \
*emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \
@@ -389,7 +301,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
} else {
assert(i == 3); // should be true; max 4 args is checked above
- ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
+ ASM_MOV_LOCAL_REG(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
}
}
#endif
@@ -418,14 +330,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
#endif
// set code_state.fun_bc
- ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_1, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t));
+ ASM_MOV_LOCAL_REG(emit->as, offsetof(mp_code_state_t, fun_bc) / sizeof(uintptr_t), REG_ARG_1);
// set code_state.ip (offset from start of this function to prelude info)
// XXX this encoding may change size
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), REG_ARG_1);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, offsetof(mp_code_state_t, ip) / sizeof(uintptr_t), emit->prelude_offset, REG_ARG_1);
// put address of code_state into first arg
- ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1);
+ ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, 0);
// call mp_setup_code_state to prepare code_state structure
#if N_THUMB
@@ -438,11 +350,11 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
// cache some locals in registers
if (scope->num_locals > 0) {
- ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1);
+ ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_1, STATE_START + emit->n_state - 1 - 0);
if (scope->num_locals > 1) {
- ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2);
+ ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_2, STATE_START + emit->n_state - 1 - 1);
if (scope->num_locals > 2) {
- ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3);
+ ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, STATE_START + emit->n_state - 1 - 2);
}
}
}
@@ -606,7 +518,7 @@ STATIC void need_reg_single(emit_t *emit, int reg_needed, int skip_stack_pos) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG && si->data.u_reg == reg_needed) {
si->kind = STACK_VALUE;
- ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
+ ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg);
}
}
}
@@ -617,7 +529,7 @@ STATIC void need_reg_all(emit_t *emit) {
stack_info_t *si = &emit->stack_info[i];
if (si->kind == STACK_REG) {
si->kind = STACK_VALUE;
- ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
+ ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg);
}
}
}
@@ -629,7 +541,7 @@ STATIC void need_stack_settled(emit_t *emit) {
if (si->kind == STACK_REG) {
DEBUG_printf(" reg(%u) to local(%u)\n", si->data.u_reg, emit->stack_start + i);
si->kind = STACK_VALUE;
- ASM_MOV_REG_TO_LOCAL(emit->as, si->data.u_reg, emit->stack_start + i);
+ ASM_MOV_LOCAL_REG(emit->as, emit->stack_start + i, si->data.u_reg);
}
}
for (int i = 0; i < emit->stack_size; i++) {
@@ -637,7 +549,7 @@ STATIC void need_stack_settled(emit_t *emit) {
if (si->kind == STACK_IMM) {
DEBUG_printf(" imm(" INT_FMT ") to local(%u)\n", si->data.u_imm, emit->stack_start + i);
si->kind = STACK_VALUE;
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + i, REG_TEMP0);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + i, si->data.u_imm, REG_TEMP0);
}
}
}
@@ -649,7 +561,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re
*vtype = si->vtype;
switch (si->kind) {
case STACK_VALUE:
- ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - pos, reg_dest);
+ ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - pos);
break;
case STACK_REG:
@@ -659,7 +571,7 @@ STATIC void emit_access_stack(emit_t *emit, int pos, vtype_kind_t *vtype, int re
break;
case STACK_IMM:
- ASM_MOV_IMM_TO_REG(emit->as, si->data.u_imm, reg_dest);
+ ASM_MOV_REG_IMM(emit->as, reg_dest, si->data.u_imm);
break;
}
}
@@ -671,7 +583,7 @@ STATIC void emit_fold_stack_top(emit_t *emit, int reg_dest) {
si[0] = si[1];
if (si->kind == STACK_VALUE) {
// if folded element was on the stack we need to put it in a register
- ASM_MOV_LOCAL_TO_REG(emit->as, emit->stack_start + emit->stack_size - 1, reg_dest);
+ ASM_MOV_REG_LOCAL(emit->as, reg_dest, emit->stack_start + emit->stack_size - 1);
si->kind = STACK_REG;
si->data.u_reg = reg_dest;
}
@@ -765,30 +677,30 @@ STATIC void emit_call(emit_t *emit, mp_fun_kind_t fun_kind) {
STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
need_reg_all(emit);
- ASM_MOV_IMM_TO_REG(emit->as, arg_val, arg_reg);
+ ASM_MOV_REG_IMM(emit->as, arg_reg, arg_val);
ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
}
// the first arg is stored in the code aligned on a mp_uint_t boundary
STATIC void emit_call_with_imm_arg_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg) {
need_reg_all(emit);
- ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val, arg_reg);
+ ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg, arg_val);
ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
}
STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2) {
need_reg_all(emit);
- ASM_MOV_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
- ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
+ ASM_MOV_REG_IMM(emit->as, arg_reg1, arg_val1);
+ ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2);
ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
}
// the first arg is stored in the code aligned on a mp_uint_t boundary
STATIC void emit_call_with_3_imm_args_and_first_aligned(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val1, int arg_reg1, mp_int_t arg_val2, int arg_reg2, mp_int_t arg_val3, int arg_reg3) {
need_reg_all(emit);
- ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, arg_val1, arg_reg1);
- ASM_MOV_IMM_TO_REG(emit->as, arg_val2, arg_reg2);
- ASM_MOV_IMM_TO_REG(emit->as, arg_val3, arg_reg3);
+ ASM_MOV_REG_ALIGNED_IMM(emit->as, arg_reg1, arg_val1);
+ ASM_MOV_REG_IMM(emit->as, arg_reg2, arg_val2);
+ ASM_MOV_REG_IMM(emit->as, arg_reg3, arg_val3);
ASM_CALL_IND(emit->as, mp_fun_table[fun_kind], fun_kind);
}
@@ -808,19 +720,19 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
si->kind = STACK_VALUE;
switch (si->vtype) {
case VTYPE_PYOBJ:
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, si->data.u_imm, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, si->data.u_imm, reg_dest);
break;
case VTYPE_BOOL:
if (si->data.u_imm == 0) {
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_false, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_false, reg_dest);
} else {
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (mp_uint_t)mp_const_true, emit->stack_start + emit->stack_size - 1 - i, reg_dest);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (mp_uint_t)mp_const_true, reg_dest);
}
si->vtype = VTYPE_PYOBJ;
break;
case VTYPE_INT:
case VTYPE_UINT:
- ASM_MOV_IMM_TO_LOCAL_USING(emit->as, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), emit->stack_start + emit->stack_size - 1 - i, reg_dest);
+ ASM_MOV_LOCAL_IMM_VIA(emit->as, emit->stack_start + emit->stack_size - 1 - i, (uintptr_t)MP_OBJ_NEW_SMALL_INT(si->data.u_imm), reg_dest);
si->vtype = VTYPE_PYOBJ;
break;
default:
@@ -838,9 +750,9 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
stack_info_t *si = &emit->stack_info[emit->stack_size - 1 - i];
if (si->vtype != VTYPE_PYOBJ) {
mp_uint_t local_num = emit->stack_start + emit->stack_size - 1 - i;
- ASM_MOV_LOCAL_TO_REG(emit->as, local_num, REG_ARG_1);
+ ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, local_num);
emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, si->vtype, REG_ARG_2); // arg2 = type
- ASM_MOV_REG_TO_LOCAL(emit->as, REG_RET, local_num);
+ ASM_MOV_LOCAL_REG(emit->as, local_num, REG_RET);
si->vtype = VTYPE_PYOBJ;
DEBUG_printf(" convert_native_to_obj(local_num=" UINT_FMT ")\n", local_num);
}
@@ -848,7 +760,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_pop(emit_t *emit, mp_uint_t reg_de
// Adujust the stack for a pop of n_pop items, and load the stack pointer into reg_dest.
adjust_stack(emit, -n_pop);
- ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
+ ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size);
}
// vtype of all n_push objects is VTYPE_PYOBJ
@@ -858,7 +770,7 @@ STATIC void emit_get_stack_pointer_to_reg_for_push(emit_t *emit, mp_uint_t reg_d
emit->stack_info[emit->stack_size + i].kind = STACK_VALUE;
emit->stack_info[emit->stack_size + i].vtype = VTYPE_PYOBJ;
}
- ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, emit->stack_start + emit->stack_size, reg_dest);
+ ASM_MOV_REG_LOCAL_ADDR(emit->as, reg_dest, emit->stack_start + emit->stack_size);
adjust_stack(emit, n_push);
}
@@ -881,7 +793,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) {
stack_info_t *top = peek_stack(emit, 0);
if (top->vtype == VTYPE_PTR_NONE) {
emit_pre_pop_discard(emit);
- ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_ARG_2);
+ ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)mp_const_none);
} else {
vtype_kind_t vtype_fromlist;
emit_pre_pop_reg(emit, &vtype_fromlist, REG_ARG_2);
@@ -891,7 +803,7 @@ STATIC void emit_native_import_name(emit_t *emit, qstr qst) {
// level argument should be an immediate integer
top = peek_stack(emit, 0);
assert(top->vtype == VTYPE_INT && top->kind == STACK_IMM);
- ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm), REG_ARG_3);
+ ASM_MOV_REG_IMM(emit->as, REG_ARG_3, (mp_uint_t)MP_OBJ_NEW_SMALL_INT(top->data.u_imm));
emit_pre_pop_discard(emit);
} else {
@@ -925,6 +837,16 @@ STATIC void emit_native_import_star(emit_t *emit) {
emit_post(emit);
}
+STATIC void emit_native_import(emit_t *emit, qstr qst, int kind) {
+ if (kind == MP_EMIT_IMPORT_NAME) {
+ emit_native_import_name(emit, qst);
+ } else if (kind == MP_EMIT_IMPORT_FROM) {
+ emit_native_import_from(emit, qst);
+ } else {
+ emit_native_import_star(emit);
+ }
+}
+
STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
DEBUG_printf("load_const_tok(tok=%u)\n", tok);
emit_native_pre(emit);
@@ -981,7 +903,7 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst) {
STATIC void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) {
emit_native_pre(emit);
need_reg_single(emit, REG_RET, 0);
- ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET);
+ ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_RET, (mp_uint_t)obj);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
@@ -1006,9 +928,9 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
} else {
need_reg_single(emit, REG_TEMP0, 0);
if (emit->do_viper_types) {
- ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
+ ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
} else {
- ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0);
+ ASM_MOV_REG_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num);
}
emit_post_push_reg(emit, vtype, REG_TEMP0);
}
@@ -1026,33 +948,47 @@ STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num)
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
-STATIC void emit_native_load_name(emit_t *emit, qstr qst) {
- DEBUG_printf("load_name(%s)\n", qstr_str(qst));
- emit_native_pre(emit);
- emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, qst, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
+STATIC void emit_native_load_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
+ emit_native_load_fast(emit, qst, local_num);
+ } else {
+ emit_native_load_deref(emit, qst, local_num);
+ }
}
-STATIC void emit_native_load_global(emit_t *emit, qstr qst) {
- DEBUG_printf("load_global(%s)\n", qstr_str(qst));
+STATIC void emit_native_load_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_LOAD_NAME);
+ MP_STATIC_ASSERT(MP_F_LOAD_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_LOAD_GLOBAL);
emit_native_pre(emit);
- // check for builtin casting operators
- if (emit->do_viper_types && qst == MP_QSTR_int) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT);
- } else if (emit->do_viper_types && qst == MP_QSTR_uint) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT);
- } else if (emit->do_viper_types && qst == MP_QSTR_ptr) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR);
- } else if (emit->do_viper_types && qst == MP_QSTR_ptr8) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8);
- } else if (emit->do_viper_types && qst == MP_QSTR_ptr16) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16);
- } else if (emit->do_viper_types && qst == MP_QSTR_ptr32) {
- emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32);
+ if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {
+ DEBUG_printf("load_name(%s)\n", qstr_str(qst));
} else {
- emit_call_with_imm_arg(emit, MP_F_LOAD_GLOBAL, qst, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
+ DEBUG_printf("load_global(%s)\n", qstr_str(qst));
+ if (emit->do_viper_types) {
+ // check for builtin casting operators
+ if (qst == MP_QSTR_int) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_INT);
+ return;
+ } else if (qst == MP_QSTR_uint) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_UINT);
+ return;
+ } else if (qst == MP_QSTR_ptr) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR);
+ return;
+ } else if (qst == MP_QSTR_ptr8) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR8);
+ return;
+ } else if (qst == MP_QSTR_ptr16) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR16);
+ return;
+ } else if (qst == MP_QSTR_ptr32) {
+ emit_post_push_imm(emit, VTYPE_BUILTIN_CAST, VTYPE_PTR32);
+ return;
+ }
+ }
}
+ emit_call_with_imm_arg(emit, MP_F_LOAD_NAME + kind, qst, REG_ARG_1);
+ emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
STATIC void emit_native_load_attr(emit_t *emit, qstr qst) {
@@ -1134,7 +1070,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
reg_base = reg_index;
}
@@ -1151,7 +1087,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base
reg_base = reg_index;
}
@@ -1168,7 +1104,7 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base
reg_base = reg_index;
}
@@ -1233,9 +1169,9 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num)
} else {
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
if (emit->do_viper_types) {
- ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
+ ASM_MOV_LOCAL_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
} else {
- ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num);
+ ASM_MOV_LOCAL_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0);
}
}
emit_post(emit);
@@ -1266,25 +1202,33 @@ STATIC void emit_native_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num)
emit_post(emit);
}
-STATIC void emit_native_store_name(emit_t *emit, qstr qst) {
- // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type))
- vtype_kind_t vtype;
- emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
- assert(vtype == VTYPE_PYOBJ);
- emit_call_with_imm_arg(emit, MP_F_STORE_NAME, qst, REG_ARG_1); // arg1 = name
- emit_post(emit);
+STATIC void emit_native_store_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
+ emit_native_store_fast(emit, qst, local_num);
+ } else {
+ emit_native_store_deref(emit, qst, local_num);
+ }
}
-STATIC void emit_native_store_global(emit_t *emit, qstr qst) {
- vtype_kind_t vtype = peek_vtype(emit, 0);
- if (vtype == VTYPE_PYOBJ) {
+STATIC void emit_native_store_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_STORE_NAME);
+ MP_STATIC_ASSERT(MP_F_STORE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_STORE_GLOBAL);
+ if (kind == MP_EMIT_IDOP_GLOBAL_NAME) {
+ // mp_store_name, but needs conversion of object (maybe have mp_viper_store_name(obj, type))
+ vtype_kind_t vtype;
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
+ assert(vtype == VTYPE_PYOBJ);
} else {
- emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
- emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type
- ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
+ vtype_kind_t vtype = peek_vtype(emit, 0);
+ if (vtype == VTYPE_PYOBJ) {
+ emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
+ } else {
+ emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
+ emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, vtype, REG_ARG_2); // arg2 = type
+ ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_RET);
+ }
}
- emit_call_with_imm_arg(emit, MP_F_STORE_GLOBAL, qst, REG_ARG_1); // arg1 = name
+ emit_call_with_imm_arg(emit, MP_F_STORE_NAME + kind, qst, REG_ARG_1); // arg1 = name
emit_post(emit);
}
@@ -1354,7 +1298,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
#if N_ARM
asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
return;
@@ -1375,7 +1319,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value << 1, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1);
#if N_ARM
asm_arm_strh_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
return;
@@ -1396,7 +1340,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
break;
}
#endif
- ASM_MOV_IMM_TO_REG(emit->as, index_value << 2, reg_index);
+ ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2);
#if N_ARM
asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
return;
@@ -1477,30 +1421,23 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
}
}
-STATIC void emit_native_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
- // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL
- // to mark deleted vars but then every var would need to be checked on
- // each access. Very inefficient, so just set value to None to enable GC.
- emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE);
- emit_native_store_fast(emit, qst, local_num);
-}
-
-STATIC void emit_native_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
- // TODO implement me!
- (void)emit;
- (void)qst;
- (void)local_num;
-}
-
-STATIC void emit_native_delete_name(emit_t *emit, qstr qst) {
- emit_native_pre(emit);
- emit_call_with_imm_arg(emit, MP_F_DELETE_NAME, qst, REG_ARG_1);
- emit_post(emit);
+STATIC void emit_native_delete_local(emit_t *emit, qstr qst, mp_uint_t local_num, int kind) {
+ if (kind == MP_EMIT_IDOP_LOCAL_FAST) {
+ // TODO: This is not compliant implementation. We could use MP_OBJ_SENTINEL
+ // to mark deleted vars but then every var would need to be checked on
+ // each access. Very inefficient, so just set value to None to enable GC.
+ emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE);
+ emit_native_store_fast(emit, qst, local_num);
+ } else {
+ // TODO implement me!
+ }
}
-STATIC void emit_native_delete_global(emit_t *emit, qstr qst) {
+STATIC void emit_native_delete_global(emit_t *emit, qstr qst, int kind) {
+ MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_NAME == MP_F_DELETE_NAME);
+ MP_STATIC_ASSERT(MP_F_DELETE_NAME + MP_EMIT_IDOP_GLOBAL_GLOBAL == MP_F_DELETE_GLOBAL);
emit_native_pre(emit);
- emit_call_with_imm_arg(emit, MP_F_DELETE_GLOBAL, qst, REG_ARG_1);
+ emit_call_with_imm_arg(emit, MP_F_DELETE_NAME + kind, qst, REG_ARG_1);
emit_post(emit);
}
@@ -1520,6 +1457,26 @@ STATIC void emit_native_delete_subscr(emit_t *emit) {
emit_call_with_imm_arg(emit, MP_F_OBJ_SUBSCR, (mp_uint_t)MP_OBJ_NULL, REG_ARG_3);
}
+STATIC void emit_native_subscr(emit_t *emit, int kind) {
+ if (kind == MP_EMIT_SUBSCR_LOAD) {
+ emit_native_load_subscr(emit);
+ } else if (kind == MP_EMIT_SUBSCR_STORE) {
+ emit_native_store_subscr(emit);
+ } else {
+ emit_native_delete_subscr(emit);
+ }
+}
+
+STATIC void emit_native_attr(emit_t *emit, qstr qst, int kind) {
+ if (kind == MP_EMIT_ATTR_LOAD) {
+ emit_native_load_attr(emit, qst);
+ } else if (kind == MP_EMIT_ATTR_STORE) {
+ emit_native_store_attr(emit, qst);
+ } else {
+ emit_native_delete_attr(emit, qst);
+ }
+}
+
STATIC void emit_native_dup_top(emit_t *emit) {
DEBUG_printf("dup_top\n");
vtype_kind_t vtype;
@@ -1613,16 +1570,11 @@ STATIC void emit_native_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label)
emit_post(emit);
}
-STATIC void emit_native_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
+STATIC void emit_native_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
(void)except_depth;
emit_native_jump(emit, label & ~MP_EMIT_BREAK_FROM_FOR); // TODO properly
}
-STATIC void emit_native_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
- (void)except_depth;
- emit_native_jump(emit, label); // TODO properly
-}
-
STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
// the context manager is on the top of the stack
// stack: (..., ctx_mgr)
@@ -1665,6 +1617,21 @@ STATIC void emit_native_setup_with(emit_t *emit, mp_uint_t label) {
// stack: (..., __exit__, self, as_value, nlr_buf, as_value)
}
+STATIC void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) {
+ if (kind == MP_EMIT_SETUP_BLOCK_WITH) {
+ emit_native_setup_with(emit, label);
+ } else {
+ // Set up except and finally
+ emit_native_pre(emit);
+ // need to commit stack because we may jump elsewhere
+ need_stack_settled(emit);
+ emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
+ emit_call(emit, MP_F_NLR_PUSH);
+ ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
+ emit_post(emit);
+ }
+}
+
STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
// note: label+1 is available as an auxiliary label
@@ -1734,20 +1701,6 @@ STATIC void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) {
emit_native_label_assign(emit, label + 1);
}
-STATIC void emit_native_setup_except(emit_t *emit, mp_uint_t label) {
- emit_native_pre(emit);
- // need to commit stack because we may jump elsewhere
- need_stack_settled(emit);
- emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_1, sizeof(nlr_buf_t) / sizeof(mp_uint_t)); // arg1 = pointer to nlr buf
- emit_call(emit, MP_F_NLR_PUSH);
- ASM_JUMP_IF_REG_NONZERO(emit->as, REG_RET, label);
- emit_post(emit);
-}
-
-STATIC void emit_native_setup_finally(emit_t *emit, mp_uint_t label) {
- emit_native_setup_except(emit, label);
-}
-
STATIC void emit_native_end_finally(emit_t *emit) {
// logic:
// exc = pop_stack
@@ -1773,7 +1726,7 @@ STATIC void emit_native_get_iter(emit_t *emit, bool use_stack) {
emit_call(emit, MP_F_NATIVE_GETITER);
} else {
// mp_getiter will allocate the iter_buf on the heap
- ASM_MOV_IMM_TO_REG(emit->as, 0, REG_ARG_2);
+ ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0);
emit_call(emit, MP_F_NATIVE_GETITER);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
@@ -1784,7 +1737,7 @@ STATIC void emit_native_for_iter(emit_t *emit, mp_uint_t label) {
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_1, MP_OBJ_ITER_BUF_NSLOTS);
adjust_stack(emit, MP_OBJ_ITER_BUF_NSLOTS);
emit_call(emit, MP_F_NATIVE_ITERNEXT);
- ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)MP_OBJ_STOP_ITERATION, REG_TEMP1);
+ ASM_MOV_REG_IMM(emit->as, REG_TEMP1, (mp_uint_t)MP_OBJ_STOP_ITERATION);
ASM_JUMP_IF_REG_EQ(emit->as, REG_RET, REG_TEMP1, label);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
@@ -1998,26 +1951,29 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
}
}
-STATIC void emit_native_build_tuple(emit_t *emit, mp_uint_t n_args) {
+#if MICROPY_PY_BUILTINS_SLICE
+STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args);
+#endif
+
+STATIC void emit_native_build(emit_t *emit, mp_uint_t n_args, int kind) {
// for viper: call runtime, with types of args
// if wrapped in byte_array, or something, allocates memory and fills it
+ MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_TUPLE == MP_F_BUILD_TUPLE);
+ MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_LIST == MP_F_BUILD_LIST);
+ MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_MAP == MP_F_BUILD_MAP);
+ MP_STATIC_ASSERT(MP_F_BUILD_TUPLE + MP_EMIT_BUILD_SET == MP_F_BUILD_SET);
+ #if MICROPY_PY_BUILTINS_SLICE
+ if (kind == MP_EMIT_BUILD_SLICE) {
+ emit_native_build_slice(emit, n_args);
+ return;
+ }
+ #endif
emit_native_pre(emit);
- emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
- emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE, n_args, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple
-}
-
-STATIC void emit_native_build_list(emit_t *emit, mp_uint_t n_args) {
- emit_native_pre(emit);
- emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
- emit_call_with_imm_arg(emit, MP_F_BUILD_LIST, n_args, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new list
-}
-
-STATIC void emit_native_build_map(emit_t *emit, mp_uint_t n_args) {
- emit_native_pre(emit);
- emit_call_with_imm_arg(emit, MP_F_BUILD_MAP, n_args, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new map
+ if (kind == MP_EMIT_BUILD_TUPLE || kind == MP_EMIT_BUILD_LIST || kind == MP_EMIT_BUILD_SET) {
+ emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
+ }
+ emit_call_with_imm_arg(emit, MP_F_BUILD_TUPLE + kind, n_args, REG_ARG_1);
+ emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new tuple/list/map/set
}
STATIC void emit_native_store_map(emit_t *emit) {
@@ -2030,15 +1986,6 @@ STATIC void emit_native_store_map(emit_t *emit) {
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // map
}
-#if MICROPY_PY_BUILTINS_SET
-STATIC void emit_native_build_set(emit_t *emit, mp_uint_t n_args) {
- emit_native_pre(emit);
- emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, n_args); // pointer to items
- emit_call_with_imm_arg(emit, MP_F_BUILD_SET, n_args, REG_ARG_1);
- emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); // new set
-}
-#endif
-
#if MICROPY_PY_BUILTINS_SLICE
STATIC void emit_native_build_slice(emit_t *emit, mp_uint_t n_args) {
DEBUG_printf("build_slice %d\n", n_args);
@@ -2128,12 +2075,12 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_c
emit_native_pre(emit);
if (n_pos_defaults == 0 && n_kw_defaults == 0) {
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over);
- ASM_MOV_IMM_TO_REG(emit->as, n_closed_over, REG_ARG_2);
+ ASM_MOV_REG_IMM(emit->as, REG_ARG_2, n_closed_over);
} else {
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_closed_over + 2);
- ASM_MOV_IMM_TO_REG(emit->as, 0x100 | n_closed_over, REG_ARG_2);
+ ASM_MOV_REG_IMM(emit->as, REG_ARG_2, 0x100 | n_closed_over);
}
- ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)scope->raw_code, REG_ARG_1);
+ ASM_MOV_REG_ALIGNED_IMM(emit->as, REG_ARG_1, (mp_uint_t)scope->raw_code);
ASM_CALL_IND(emit->as, mp_fun_table[MP_F_MAKE_CLOSURE_FROM_RAW_CODE], MP_F_MAKE_CLOSURE_FROM_RAW_CODE);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
}
@@ -2212,9 +2159,9 @@ STATIC void emit_native_return_value(emit_t *emit) {
if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) {
emit_pre_pop_discard(emit);
if (emit->return_vtype == VTYPE_PYOBJ) {
- ASM_MOV_IMM_TO_REG(emit->as, (mp_uint_t)mp_const_none, REG_RET);
+ ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)mp_const_none);
} else {
- ASM_MOV_IMM_TO_REG(emit->as, 0, REG_RET);
+ ASM_MOV_REG_IMM(emit->as, REG_RET, 0);
}
} else {
vtype_kind_t vtype;
@@ -2245,16 +2192,12 @@ STATIC void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) {
emit_call(emit, MP_F_NATIVE_RAISE);
}
-STATIC void emit_native_yield_value(emit_t *emit) {
+STATIC void emit_native_yield(emit_t *emit, int kind) {
// not supported (for now)
(void)emit;
+ (void)kind;
mp_raise_NotImplementedError("native yield");
}
-STATIC void emit_native_yield_from(emit_t *emit) {
- // not supported (for now)
- (void)emit;
- mp_raise_NotImplementedError("native yield from");
-}
STATIC void emit_native_start_except_handler(emit_t *emit) {
// This instruction follows an nlr_pop, so the stack counter is back to zero, when really
@@ -2280,41 +2223,29 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_set_source_line,
{
- emit_native_load_fast,
- emit_native_load_deref,
- emit_native_load_name,
+ emit_native_load_local,
emit_native_load_global,
},
{
- emit_native_store_fast,
- emit_native_store_deref,
- emit_native_store_name,
+ emit_native_store_local,
emit_native_store_global,
},
{
- emit_native_delete_fast,
- emit_native_delete_deref,
- emit_native_delete_name,
+ emit_native_delete_local,
emit_native_delete_global,
},
emit_native_label_assign,
- emit_native_import_name,
- emit_native_import_from,
- emit_native_import_star,
+ emit_native_import,
emit_native_load_const_tok,
emit_native_load_const_small_int,
emit_native_load_const_str,
emit_native_load_const_obj,
emit_native_load_null,
- emit_native_load_attr,
emit_native_load_method,
emit_native_load_build_class,
- emit_native_load_subscr,
- emit_native_store_attr,
- emit_native_store_subscr,
- emit_native_delete_attr,
- emit_native_delete_subscr,
+ emit_native_subscr,
+ emit_native_attr,
emit_native_dup_top,
emit_native_dup_top_two,
emit_native_pop_top,
@@ -2323,12 +2254,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_jump,
emit_native_pop_jump_if,
emit_native_jump_if_or_pop,
- emit_native_break_loop,
- emit_native_continue_loop,
- emit_native_setup_with,
+ emit_native_unwind_jump,
+ emit_native_setup_block,
emit_native_with_cleanup,
- emit_native_setup_except,
- emit_native_setup_finally,
emit_native_end_finally,
emit_native_get_iter,
emit_native_for_iter,
@@ -2337,16 +2265,8 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_pop_except,
emit_native_unary_op,
emit_native_binary_op,
- emit_native_build_tuple,
- emit_native_build_list,
- emit_native_build_map,
+ emit_native_build,
emit_native_store_map,
- #if MICROPY_PY_BUILTINS_SET
- emit_native_build_set,
- #endif
- #if MICROPY_PY_BUILTINS_SLICE
- emit_native_build_slice,
- #endif
emit_native_store_comp,
emit_native_unpack_sequence,
emit_native_unpack_ex,
@@ -2356,8 +2276,7 @@ const emit_method_table_t EXPORT_FUN(method_table) = {
emit_native_call_method,
emit_native_return_value,
emit_native_raise_varargs,
- emit_native_yield_value,
- emit_native_yield_from,
+ emit_native_yield,
emit_native_start_except_handler,
emit_native_end_except_handler,
diff --git a/py/emitnthumb.c b/py/emitnthumb.c
new file mode 100644
index 000000000..2b68ca3a1
--- /dev/null
+++ b/py/emitnthumb.c
@@ -0,0 +1,15 @@
+// thumb specific stuff
+
+#include "py/mpconfig.h"
+
+#if MICROPY_EMIT_THUMB
+
+// this is defined so that the assembler exports generic assembler API macros
+#define GENERIC_ASM_API (1)
+#include "py/asmthumb.h"
+
+#define N_THUMB (1)
+#define EXPORT_FUN(name) emit_native_thumb_##name
+#include "py/emitnative.c"
+
+#endif
diff --git a/py/emitnx64.c b/py/emitnx64.c
new file mode 100644
index 000000000..b9800f636
--- /dev/null
+++ b/py/emitnx64.c
@@ -0,0 +1,15 @@
+// x64 specific stuff
+
+#include "py/mpconfig.h"
+
+#if MICROPY_EMIT_X64
+
+// This is defined so that the assembler exports generic assembler API macros
+#define GENERIC_ASM_API (1)
+#include "py/asmx64.h"
+
+#define N_X64 (1)
+#define EXPORT_FUN(name) emit_native_x64_##name
+#include "py/emitnative.c"
+
+#endif
diff --git a/py/emitnx86.c b/py/emitnx86.c
new file mode 100644
index 000000000..5d2bbb267
--- /dev/null
+++ b/py/emitnx86.c
@@ -0,0 +1,68 @@
+// x86 specific stuff
+
+#include "py/mpconfig.h"
+#include "py/runtime0.h"
+
+#if MICROPY_EMIT_X86
+
+// This is defined so that the assembler exports generic assembler API macros
+#define GENERIC_ASM_API (1)
+#include "py/asmx86.h"
+
+// x86 needs a table to know how many args a given function has
+STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
+ [MP_F_CONVERT_OBJ_TO_NATIVE] = 2,
+ [MP_F_CONVERT_NATIVE_TO_OBJ] = 2,
+ [MP_F_LOAD_NAME] = 1,
+ [MP_F_LOAD_GLOBAL] = 1,
+ [MP_F_LOAD_BUILD_CLASS] = 0,
+ [MP_F_LOAD_ATTR] = 2,
+ [MP_F_LOAD_METHOD] = 3,
+ [MP_F_LOAD_SUPER_METHOD] = 2,
+ [MP_F_STORE_NAME] = 2,
+ [MP_F_STORE_GLOBAL] = 2,
+ [MP_F_STORE_ATTR] = 3,
+ [MP_F_OBJ_SUBSCR] = 3,
+ [MP_F_OBJ_IS_TRUE] = 1,
+ [MP_F_UNARY_OP] = 2,
+ [MP_F_BINARY_OP] = 3,
+ [MP_F_BUILD_TUPLE] = 2,
+ [MP_F_BUILD_LIST] = 2,
+ [MP_F_LIST_APPEND] = 2,
+ [MP_F_BUILD_MAP] = 1,
+ [MP_F_STORE_MAP] = 3,
+ #if MICROPY_PY_BUILTINS_SET
+ [MP_F_BUILD_SET] = 2,
+ [MP_F_STORE_SET] = 2,
+ #endif
+ [MP_F_MAKE_FUNCTION_FROM_RAW_CODE] = 3,
+ [MP_F_NATIVE_CALL_FUNCTION_N_KW] = 3,
+ [MP_F_CALL_METHOD_N_KW] = 3,
+ [MP_F_CALL_METHOD_N_KW_VAR] = 3,
+ [MP_F_NATIVE_GETITER] = 2,
+ [MP_F_NATIVE_ITERNEXT] = 1,
+ [MP_F_NLR_PUSH] = 1,
+ [MP_F_NLR_POP] = 0,
+ [MP_F_NATIVE_RAISE] = 1,
+ [MP_F_IMPORT_NAME] = 3,
+ [MP_F_IMPORT_FROM] = 2,
+ [MP_F_IMPORT_ALL] = 1,
+ #if MICROPY_PY_BUILTINS_SLICE
+ [MP_F_NEW_SLICE] = 3,
+ #endif
+ [MP_F_UNPACK_SEQUENCE] = 3,
+ [MP_F_UNPACK_EX] = 3,
+ [MP_F_DELETE_NAME] = 1,
+ [MP_F_DELETE_GLOBAL] = 1,
+ [MP_F_NEW_CELL] = 1,
+ [MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
+ [MP_F_SETUP_CODE_STATE] = 5,
+ [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,
+ [MP_F_SMALL_INT_MODULO] = 2,
+};
+
+#define N_X86 (1)
+#define EXPORT_FUN(name) emit_native_x86_##name
+#include "py/emitnative.c"
+
+#endif
diff --git a/py/emitnxtensa.c b/py/emitnxtensa.c
new file mode 100644
index 000000000..1a423e21e
--- /dev/null
+++ b/py/emitnxtensa.c
@@ -0,0 +1,15 @@
+// Xtensa specific stuff
+
+#include "py/mpconfig.h"
+
+#if MICROPY_EMIT_XTENSA
+
+// this is defined so that the assembler exports generic assembler API macros
+#define GENERIC_ASM_API (1)
+#include "py/asmxtensa.h"
+
+#define N_XTENSA (1)
+#define EXPORT_FUN(name) emit_native_xtensa_##name
+#include "py/emitnative.c"
+
+#endif
diff --git a/py/formatfloat.c b/py/formatfloat.c
index 4228f99ff..dc7fc1d1f 100644
--- a/py/formatfloat.c
+++ b/py/formatfloat.c
@@ -258,7 +258,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
}
// It can be that f was right on the edge of an entry in pos_pow needs to be reduced
- if (f >= FPCONST(10.0)) {
+ if ((int)f >= 10) {
e += 1;
f *= FPCONST(0.1);
}
@@ -330,7 +330,11 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
// Print the digits of the mantissa
for (int i = 0; i < num_digits; ++i, --dec) {
int32_t d = (int32_t)f;
- *s++ = '0' + d;
+ if (d < 0) {
+ *s++ = '0';
+ } else {
+ *s++ = '0' + d;
+ }
if (dec == 0 && prec > 0) {
*s++ = '.';
}
@@ -341,7 +345,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
// Round
// If we print non-exponential format (i.e. 'f'), but a digit we're going
// to round by (e) is too far away, then there's nothing to round.
- if ((org_fmt != 'f' || e <= 1) && f >= FPCONST(5.0)) {
+ if ((org_fmt != 'f' || e <= num_digits) && f >= FPCONST(5.0)) {
char *rs = s;
rs--;
while (1) {
diff --git a/py/gc.c b/py/gc.c
index 2c2354e4c..1f5cd8d01 100755
--- a/py/gc.c
+++ b/py/gc.c
@@ -47,6 +47,10 @@
// make this 1 to dump the heap each time it changes
#define EXTENSIVE_HEAP_PROFILING (0)
+// make this 1 to zero out swept memory to more eagerly
+// detect untraced object still in use
+#define CLEAR_ON_SWEEP (0)
+
#define WORDS_PER_BLOCK ((MICROPY_BYTES_PER_GC_BLOCK) / BYTES_PER_WORD)
#define BYTES_PER_BLOCK (MICROPY_BYTES_PER_GC_BLOCK)
@@ -201,29 +205,22 @@ bool gc_is_locked(void) {
&& ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \
)
-// ptr should be of type void*
-#define VERIFY_MARK_AND_PUSH(ptr) \
- do { \
- if (VERIFY_PTR(ptr)) { \
- size_t _block = BLOCK_FROM_PTR(ptr); \
- if (ATB_GET_KIND(_block) == AT_HEAD) { \
- /* an unmarked head, mark it, and push it on gc stack */ \
- DEBUG_printf("gc_mark(%p)\n", ptr); \
- ATB_HEAD_TO_MARK(_block); \
- if (MP_STATE_MEM(gc_sp) < &MP_STATE_MEM(gc_stack)[MICROPY_ALLOC_GC_STACK_SIZE]) { \
- *MP_STATE_MEM(gc_sp)++ = _block; \
- } else { \
- MP_STATE_MEM(gc_stack_overflow) = 1; \
- } \
- } \
- } \
- } while (0)
-
-STATIC void gc_drain_stack(void) {
- while (MP_STATE_MEM(gc_sp) > MP_STATE_MEM(gc_stack)) {
- // pop the next block off the stack
- size_t block = *--MP_STATE_MEM(gc_sp);
+#ifndef TRACE_MARK
+#if DEBUG_PRINT
+#define TRACE_MARK(block, ptr) DEBUG_printf("gc_mark(%p)\n", ptr)
+#else
+#define TRACE_MARK(block, ptr)
+#endif
+#endif
+// Take the given block as the topmost block on the stack. Check all it's
+// children: mark the unmarked child blocks and put those newly marked
+// blocks on the stack. When all children have been checked, pop off the
+// topmost block on the stack and repeat with that one.
+STATIC void gc_mark_subtree(size_t block) {
+ // Start with the block passed in the argument.
+ size_t sp = 0;
+ for (;;) {
// work out number of consecutive blocks in the chain starting with this one
size_t n_blocks = 0;
do {
@@ -234,22 +231,41 @@ STATIC void gc_drain_stack(void) {
void **ptrs = (void**)PTR_FROM_BLOCK(block);
for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void*); i > 0; i--, ptrs++) {
void *ptr = *ptrs;
- VERIFY_MARK_AND_PUSH(ptr);
+ if (VERIFY_PTR(ptr)) {
+ // Mark and push this pointer
+ size_t childblock = BLOCK_FROM_PTR(ptr);
+ if (ATB_GET_KIND(childblock) == AT_HEAD) {
+ // an unmarked head, mark it, and push it on gc stack
+ TRACE_MARK(childblock, ptr);
+ ATB_HEAD_TO_MARK(childblock);
+ if (sp < MICROPY_ALLOC_GC_STACK_SIZE) {
+ MP_STATE_MEM(gc_stack)[sp++] = childblock;
+ } else {
+ MP_STATE_MEM(gc_stack_overflow) = 1;
+ }
+ }
+ }
}
+
+ // Are there any blocks on the stack?
+ if (sp == 0) {
+ break; // No, stack is empty, we're done.
+ }
+
+ // pop the next block off the stack
+ block = MP_STATE_MEM(gc_stack)[--sp];
}
}
STATIC void gc_deal_with_stack_overflow(void) {
while (MP_STATE_MEM(gc_stack_overflow)) {
MP_STATE_MEM(gc_stack_overflow) = 0;
- MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
// scan entire memory looking for blocks which have been marked but not their children
for (size_t block = 0; block < MP_STATE_MEM(gc_alloc_table_byte_len) * BLOCKS_PER_ATB; block++) {
// trace (again) if mark bit set
if (ATB_GET_KIND(block) == AT_MARK) {
- *MP_STATE_MEM(gc_sp)++ = block;
- gc_drain_stack();
+ gc_mark_subtree(block);
}
}
}
@@ -288,6 +304,9 @@ STATIC void gc_sweep(void) {
#endif
free_tail = 1;
ATB_ANY_TO_FREE(block);
+ #if CLEAR_ON_SWEEP
+ memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);
+ #endif
DEBUG_printf("gc_sweep(%x)\n", PTR_FROM_BLOCK(block));
#ifdef LOG_HEAP_ACTIVITY
@@ -301,6 +320,9 @@ STATIC void gc_sweep(void) {
case AT_TAIL:
if (free_tail) {
ATB_ANY_TO_FREE(block);
+ #if CLEAR_ON_SWEEP
+ memset((void*)PTR_FROM_BLOCK(block), 0, BYTES_PER_BLOCK);
+ #endif
}
break;
@@ -319,19 +341,34 @@ void gc_collect_start(void) {
MP_STATE_MEM(gc_alloc_amount) = 0;
#endif
MP_STATE_MEM(gc_stack_overflow) = 0;
- MP_STATE_MEM(gc_sp) = MP_STATE_MEM(gc_stack);
+
// Trace root pointers. This relies on the root pointers being organised
// correctly in the mp_state_ctx structure. We scan nlr_top, dict_locals,
// dict_globals, then the root pointer section of mp_state_vm.
void **ptrs = (void**)(void*)&mp_state_ctx;
- gc_collect_root(ptrs, offsetof(mp_state_ctx_t, vm.qstr_last_chunk) / sizeof(void*));
+ size_t root_start = offsetof(mp_state_ctx_t, thread.dict_locals);
+ size_t root_end = offsetof(mp_state_ctx_t, vm.qstr_last_chunk);
+ gc_collect_root(ptrs + root_start / sizeof(void*), (root_end - root_start) / sizeof(void*));
+
+ #if MICROPY_ENABLE_PYSTACK
+ // Trace root pointers from the Python stack.
+ ptrs = (void**)(void*)MP_STATE_THREAD(pystack_start);
+ gc_collect_root(ptrs, (MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start)) / sizeof(void*));
+ #endif
}
void gc_collect_root(void **ptrs, size_t len) {
for (size_t i = 0; i < len; i++) {
void *ptr = ptrs[i];
- VERIFY_MARK_AND_PUSH(ptr);
- gc_drain_stack();
+ if (VERIFY_PTR(ptr)) {
+ size_t block = BLOCK_FROM_PTR(ptr);
+ if (ATB_GET_KIND(block) == AT_HEAD) {
+ // An unmarked head: mark it, and mark all its children
+ TRACE_MARK(block, ptr);
+ ATB_HEAD_TO_MARK(block);
+ gc_mark_subtree(block);
+ }
+ }
}
}
@@ -344,6 +381,13 @@ void gc_collect_end(void) {
GC_EXIT();
}
+void gc_sweep_all(void) {
+ GC_ENTER();
+ MP_STATE_MEM(gc_lock_depth)++;
+ MP_STATE_MEM(gc_stack_overflow) = 0;
+ gc_collect_end();
+}
+
void gc_info(gc_info_t *info) {
GC_ENTER();
info->total = MP_STATE_MEM(gc_pool_end) - MP_STATE_MEM(gc_pool_start);
@@ -437,6 +481,7 @@ void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived) {
if (!collected && MP_STATE_MEM(gc_alloc_amount) >= MP_STATE_MEM(gc_alloc_threshold)) {
GC_EXIT();
gc_collect();
+ collected = 1;
GC_ENTER();
collected = true;
}
@@ -748,27 +793,18 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
void *ptr = ptr_in;
- // sanity check the ptr
- if (!VERIFY_PTR(ptr)) {
- return NULL;
- }
-
- // get first block
- size_t block = BLOCK_FROM_PTR(ptr);
-
GC_ENTER();
- // sanity check the ptr is pointing to the head of a block
- if (ATB_GET_KIND(block) != AT_HEAD) {
- GC_EXIT();
- return NULL;
- }
-
if (MP_STATE_MEM(gc_lock_depth) > 0) {
GC_EXIT();
return NULL;
}
+ // get the GC block number corresponding to this pointer
+ assert(VERIFY_PTR(ptr));
+ size_t block = BLOCK_FROM_PTR(ptr);
+ assert(ATB_GET_KIND(block) == AT_HEAD);
+
// compute number of new blocks that are requested
size_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
diff --git a/py/gc.h b/py/gc.h
index e5878e1ee..64f4b0d17 100644
--- a/py/gc.h
+++ b/py/gc.h
@@ -46,6 +46,10 @@ void gc_collect_root(void **ptrs, size_t len);
void gc_collect_end(void);
void *gc_alloc(size_t n_bytes, bool has_finaliser, bool long_lived);
+
+// Use this function to sweep the whole heap and run all finalisers
+void gc_sweep_all(void);
+
void gc_free(void *ptr); // does not call finaliser
size_t gc_nbytes(const void *ptr);
bool gc_has_finaliser(const void *ptr);
diff --git a/py/grammar.h b/py/grammar.h
index 6abb1de8c..5a5b682ac 100644
--- a/py/grammar.h
+++ b/py/grammar.h
@@ -122,8 +122,8 @@ DEF_RULE_NC(augassign, or(12), tok(DEL_PLUS_EQUAL), tok(DEL_MINUS_EQUAL), tok(DE
DEF_RULE(del_stmt, c(del_stmt), and(2), tok(KW_DEL), rule(exprlist))
DEF_RULE(pass_stmt, c(generic_all_nodes), and(1), tok(KW_PASS))
DEF_RULE_NC(flow_stmt, or(5), rule(break_stmt), rule(continue_stmt), rule(return_stmt), rule(raise_stmt), rule(yield_stmt))
-DEF_RULE(break_stmt, c(break_stmt), and(1), tok(KW_BREAK))
-DEF_RULE(continue_stmt, c(continue_stmt), and(1), tok(KW_CONTINUE))
+DEF_RULE(break_stmt, c(break_cont_stmt), and(1), tok(KW_BREAK))
+DEF_RULE(continue_stmt, c(break_cont_stmt), and(1), tok(KW_CONTINUE))
DEF_RULE(return_stmt, c(return_stmt), and(2), tok(KW_RETURN), opt_rule(testlist))
DEF_RULE(yield_stmt, c(yield_stmt), and(1), rule(yield_expr))
DEF_RULE(raise_stmt, c(raise_stmt), and(2), tok(KW_RAISE), opt_rule(raise_stmt_arg))
@@ -157,8 +157,8 @@ DEF_RULE_NC(as_name, and_ident(2), tok(KW_AS), tok(NAME))
DEF_RULE_NC(import_as_names, list_with_end, rule(import_as_name), tok(DEL_COMMA))
DEF_RULE_NC(dotted_as_names, list, rule(dotted_as_name), tok(DEL_COMMA))
DEF_RULE_NC(dotted_name, list, tok(NAME), tok(DEL_PERIOD))
-DEF_RULE(global_stmt, c(global_stmt), and(2), tok(KW_GLOBAL), rule(name_list))
-DEF_RULE(nonlocal_stmt, c(nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list))
+DEF_RULE(global_stmt, c(global_nonlocal_stmt), and(2), tok(KW_GLOBAL), rule(name_list))
+DEF_RULE(nonlocal_stmt, c(global_nonlocal_stmt), and(2), tok(KW_NONLOCAL), rule(name_list))
DEF_RULE_NC(name_list, list, tok(NAME), tok(DEL_COMMA))
DEF_RULE(assert_stmt, c(assert_stmt), and(3), tok(KW_ASSERT), rule(test), opt_rule(assert_stmt_extra))
DEF_RULE_NC(assert_stmt_extra, and_ident(2), tok(DEL_COMMA), rule(test))
@@ -231,8 +231,8 @@ DEF_RULE(lambdef_nocond, c(lambdef), and_blank(4), tok(KW_LAMBDA), opt_rule(vara
// power: atom_expr ['**' factor]
// atom_expr: 'await' atom trailer* | atom trailer*
-DEF_RULE(or_test, c(or_test), list, rule(and_test), tok(KW_OR))
-DEF_RULE(and_test, c(and_test), list, rule(not_test), tok(KW_AND))
+DEF_RULE(or_test, c(or_and_test), list, rule(and_test), tok(KW_OR))
+DEF_RULE(and_test, c(or_and_test), list, rule(not_test), tok(KW_AND))
DEF_RULE_NC(not_test, or(2), rule(not_test_2), rule(comparison))
DEF_RULE(not_test_2, c(not_test_2), and(2), tok(KW_NOT), rule(not_test))
DEF_RULE(comparison, c(comparison), list, rule(expr), rule(comp_op))
@@ -241,9 +241,9 @@ DEF_RULE_NC(comp_op_not_in, and(2), tok(KW_NOT), tok(KW_IN))
DEF_RULE_NC(comp_op_is, and(2), tok(KW_IS), opt_rule(comp_op_is_not))
DEF_RULE_NC(comp_op_is_not, and(1), tok(KW_NOT))
DEF_RULE(star_expr, c(star_expr), and(2), tok(OP_STAR), rule(expr))
-DEF_RULE(expr, c(expr), list, rule(xor_expr), tok(OP_PIPE))
-DEF_RULE(xor_expr, c(xor_expr), list, rule(and_expr), tok(OP_CARET))
-DEF_RULE(and_expr, c(and_expr), list, rule(shift_expr), tok(OP_AMPERSAND))
+DEF_RULE(expr, c(binary_op), list, rule(xor_expr), tok(OP_PIPE))
+DEF_RULE(xor_expr, c(binary_op), list, rule(and_expr), tok(OP_CARET))
+DEF_RULE(and_expr, c(binary_op), list, rule(shift_expr), tok(OP_AMPERSAND))
DEF_RULE(shift_expr, c(term), list, rule(arith_expr), rule(shift_op))
DEF_RULE_NC(shift_op, or(2), tok(OP_DBL_LESS), tok(OP_DBL_MORE))
DEF_RULE(arith_expr, c(term), list, rule(term), rule(arith_op))
@@ -290,8 +290,8 @@ DEF_RULE(trailer_period, c(trailer_period), and(2), tok(DEL_PERIOD), tok(NAME))
#if MICROPY_PY_BUILTINS_SLICE
DEF_RULE(subscriptlist, c(generic_tuple), list_with_end, rule(subscript), tok(DEL_COMMA))
DEF_RULE_NC(subscript, or(2), rule(subscript_3), rule(subscript_2))
-DEF_RULE(subscript_2, c(subscript_2), and_ident(2), rule(test), opt_rule(subscript_3))
-DEF_RULE(subscript_3, c(subscript_3), and(2), tok(DEL_COLON), opt_rule(subscript_3b))
+DEF_RULE(subscript_2, c(subscript), and_ident(2), rule(test), opt_rule(subscript_3))
+DEF_RULE(subscript_3, c(subscript), and(2), tok(DEL_COLON), opt_rule(subscript_3b))
DEF_RULE_NC(subscript_3b, or(2), rule(subscript_3c), rule(subscript_3d))
DEF_RULE_NC(subscript_3c, and(2), tok(DEL_COLON), opt_rule(test))
DEF_RULE_NC(subscript_3d, and_ident(2), rule(test), opt_rule(sliceop))
diff --git a/py/lexer.c b/py/lexer.c
index 6017d69d6..e161700b1 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -590,6 +590,8 @@ void mp_lexer_to_next(mp_lexer_t *lex) {
}
vstr_add_char(&lex->vstr, CUR_CHAR(lex));
next_char(lex);
+ } else if (is_char(lex, '_')) {
+ next_char(lex);
} else {
break;
}
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 38fde1a9c..3c0a60909 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -114,6 +114,9 @@ def parse_input_headers(infiles):
if ident == "":
# Sort empty qstr above all still
order = -200000
+ elif ident == "__dir__":
+ # Put __dir__ after empty qstr for builtin dir() to work
+ order = -190000
elif ident.startswith("__"):
order -= 100000
qstrs[ident] = (order, ident, qstr)
diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py
index 0a45c585a..4253c1147 100644
--- a/py/makeqstrdefs.py
+++ b/py/makeqstrdefs.py
@@ -73,12 +73,16 @@ def qstr_unescape(qstr):
return qstr
def process_file(f):
+ re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"")
+ re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+')
output = []
last_fname = None
for line in f:
+ if line.isspace():
+ continue
# match gcc-like output (# n "file") and msvc-like output (#line n "file")
- if line and (line[0:2] == "# " or line[0:5] == "#line"):
- m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line)
+ if line.startswith(('# ', '#line')):
+ m = re_line.match(line)
assert m is not None
fname = m.group(1)
if not fname.endswith(".c"):
@@ -88,7 +92,7 @@ def process_file(f):
output = []
last_fname = fname
continue
- for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line):
+ for match in re_qstr.findall(line):
name = match.replace('MP_QSTR_', '')
if name not in QSTRING_BLACK_LIST:
output.append('Q(' + qstr_unescape(name) + ')')
diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py
index 1f82d5933..89a604aeb 100644
--- a/py/makeversionhdr.py
+++ b/py/makeversionhdr.py
@@ -100,7 +100,7 @@ def make_version_header(filename):
# Only write the file if we need to
if write_file:
- print("Generating %s" % filename)
+ print("GEN %s" % filename)
with open(filename, 'w') as f:
f.write(file_data)
diff --git a/py/malloc.c b/py/malloc.c
index d6983ffdf..f190582ab 100644
--- a/py/malloc.c
+++ b/py/malloc.c
@@ -39,6 +39,9 @@
#endif
#if MICROPY_MEM_STATS
+#if !MICROPY_MALLOC_USES_ALLOCATED_SIZE
+#error MICROPY_MEM_STATS requires MICROPY_MALLOC_USES_ALLOCATED_SIZE
+#endif
#define UPDATE_PEAK() { if (MP_STATE_MEM(current_bytes_allocated) > MP_STATE_MEM(peak_bytes_allocated)) MP_STATE_MEM(peak_bytes_allocated) = MP_STATE_MEM(current_bytes_allocated); }
#endif
@@ -117,9 +120,6 @@ void *m_malloc_with_finaliser(size_t num_bytes) {
void *m_malloc0(size_t num_bytes, bool long_lived) {
void *ptr = m_malloc(num_bytes, long_lived);
- if (ptr == NULL && num_bytes != 0) {
- m_malloc_fail(num_bytes);
- }
// If this config is set then the GC clears all memory, so we don't need to.
#if !MICROPY_GC_CONSERVATIVE_CLEAR
memset(ptr, 0, num_bytes);
@@ -147,7 +147,11 @@ void *m_realloc(void *ptr, size_t new_num_bytes) {
MP_STATE_MEM(current_bytes_allocated) += diff;
UPDATE_PEAK();
#endif
+ #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
+ #else
+ DEBUG_printf("realloc %p, %d : %p\n", ptr, new_num_bytes, new_ptr);
+ #endif
return new_ptr;
}
@@ -171,7 +175,11 @@ void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move) {
UPDATE_PEAK();
}
#endif
+ #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, old_num_bytes, new_num_bytes, new_ptr);
+ #else
+ DEBUG_printf("realloc %p, %d, %d : %p\n", ptr, new_num_bytes, new_ptr);
+ #endif
return new_ptr;
}
@@ -184,7 +192,11 @@ void m_free(void *ptr) {
#if MICROPY_MEM_STATS
MP_STATE_MEM(current_bytes_allocated) -= num_bytes;
#endif
+ #if MICROPY_MALLOC_USES_ALLOCATED_SIZE
DEBUG_printf("free %p, %d\n", ptr, num_bytes);
+ #else
+ DEBUG_printf("free %p\n", ptr);
+ #endif
}
#if MICROPY_MEM_STATS
diff --git a/py/map.c b/py/map.c
index 4f76b9b16..6abf4853f 100644
--- a/py/map.c
+++ b/py/map.c
@@ -33,6 +33,13 @@
#include "py/misc.h"
#include "py/runtime.h"
+#if MICROPY_DEBUG_VERBOSE // print debugging info
+#define DEBUG_PRINT (1)
+#else // don't print debugging info
+#define DEBUG_PRINT (0)
+#define DEBUG_printf(...) (void)0
+#endif
+
// Fixed empty map. Useful when need to call kw-receiving functions
// without any keywords from C, etc.
const mp_map_t mp_const_empty_map = {
@@ -114,6 +121,7 @@ void mp_map_clear(mp_map_t *map) {
STATIC void mp_map_rehash(mp_map_t *map) {
size_t old_alloc = map->alloc;
size_t new_alloc = get_hash_alloc_greater_or_equal_to(map->alloc + 1);
+ DEBUG_printf("mp_map_rehash(%p): " UINT_FMT " -> " UINT_FMT "\n", map, old_alloc, new_alloc);
mp_map_elem_t *old_table = map->table;
mp_map_elem_t *new_table = m_new0(mp_map_elem_t, new_alloc);
// If we reach this point, table resizing succeeded, now we can edit the old map.
@@ -162,6 +170,7 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
if (map->is_ordered) {
for (mp_map_elem_t *elem = &map->table[0], *top = &map->table[map->used]; elem < top; elem++) {
if (elem->key == index || (!compare_only_ptrs && mp_obj_equal(elem->key, index))) {
+ #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
if (MP_UNLIKELY(lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND)) {
// remove the found element by moving the rest of the array down
mp_obj_t value = elem->value;
@@ -172,9 +181,11 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
elem->key = MP_OBJ_NULL;
elem->value = value;
}
+ #endif
return elem;
}
}
+ #if MICROPY_PY_COLLECTIONS_ORDEREDDICT
if (MP_LIKELY(lookup_kind != MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)) {
return NULL;
}
@@ -190,6 +201,9 @@ mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t
map->all_keys_are_qstrs = 0;
}
return elem;
+ #else
+ return NULL;
+ #endif
}
// map is a hash table (not an ordered array), so do a hash lookup
diff --git a/py/misc.h b/py/misc.h
index d9a8efe7f..673568f22 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -52,6 +52,9 @@ typedef unsigned int uint;
#define _MP_STRINGIFY(x) #x
#define MP_STRINGIFY(x) _MP_STRINGIFY(x)
+// Static assertion macro
+#define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
+
/** memory allocation ******************************************/
// TODO make a lazy m_renew that can increase by a smaller amount than requested (but by at least 1 more element)
@@ -70,8 +73,10 @@ typedef unsigned int uint;
#define m_new_ll_obj_var_maybe(obj_type, var_type, var_num) ((obj_type*)m_malloc_maybe(sizeof(obj_type) + sizeof(var_type) * (var_num), true))
#if MICROPY_ENABLE_FINALISER
#define m_new_obj_with_finaliser(type) ((type*)(m_malloc_with_finaliser(sizeof(type))))
+#define m_new_obj_var_with_finaliser(type, var_type, var_num) ((type*)m_malloc_with_finaliser(sizeof(type) + sizeof(var_type) * (var_num)))
#else
#define m_new_obj_with_finaliser(type) m_new_obj(type)
+#define m_new_obj_var_with_finaliser(type, var_type, var_num) m_new_obj_var(type, var_type, var_num)
#endif
#if MICROPY_MALLOC_USES_ALLOCATED_SIZE
#define m_renew(type, ptr, old_num, new_num) ((type*)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num))))
@@ -126,8 +131,15 @@ typedef uint32_t unichar;
typedef uint unichar;
#endif
+#if MICROPY_PY_BUILTINS_STR_UNICODE
unichar utf8_get_char(const byte *s);
const byte *utf8_next_char(const byte *s);
+size_t utf8_charlen(const byte *str, size_t len);
+#else
+static inline unichar utf8_get_char(const byte *s) { return *s; }
+static inline const byte *utf8_next_char(const byte *s) { return s + 1; }
+static inline size_t utf8_charlen(const byte *str, size_t len) { (void)str; return len; }
+#endif
bool unichar_isspace(unichar c);
bool unichar_isalpha(unichar c);
@@ -140,7 +152,6 @@ bool unichar_islower(unichar c);
unichar unichar_tolower(unichar c);
unichar unichar_toupper(unichar c);
mp_uint_t unichar_xdigit_value(unichar c);
-mp_uint_t unichar_charlen(const char *str, mp_uint_t len);
#define UTF8_IS_NONASCII(ch) ((ch) & 0x80)
#define UTF8_IS_CONT(ch) (((ch) & 0xC0) == 0x80)
@@ -203,20 +214,6 @@ int DEBUG_printf(const char *fmt, ...);
extern mp_uint_t mp_verbose_flag;
-// This is useful for unicode handling. Some CPU archs has
-// special instructions for efficient implementation of this
-// function (e.g. CLZ on ARM).
-// NOTE: this function is unused at the moment
-#ifndef count_lead_ones
-static inline mp_uint_t count_lead_ones(byte val) {
- mp_uint_t c = 0;
- for (byte mask = 0x80; val & mask; mask >>= 1) {
- c++;
- }
- return c;
-}
-#endif
-
/** float internals *************/
#if MICROPY_PY_BUILTINS_FLOAT
diff --git a/py/mkenv.mk b/py/mkenv.mk
index 5f8cd902b..1b316c39d 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -67,9 +67,9 @@ CXX += -m32
LD += -m32
endif
-MAKE_FROZEN = $(TOP)/tools/make-frozen.py
+MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
-MPY_TOOL = $(TOP)/tools/mpy-tool.py
+MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py
PREPROCESS_FROZEN_MODULES = PYTHONPATH=$(TOP)/tools/python-semver $(TOP)/tools/preprocess_frozen_modules.py
all:
diff --git a/py/mkrules.mk b/py/mkrules.mk
index ed66da64b..57a51194a 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -46,16 +46,14 @@ vpath %.c . $(TOP)
$(BUILD)/%.o: %.c
$(call compile_c)
+QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR
+
# frozen.c and frozen_mpy.c are created in $(BUILD), so use our rule
# for those as well.
vpath %.c . $(BUILD)
$(BUILD)/%.o: %.c
$(call compile_c)
-# List all native flags since the current build system doesn't have
-# the MicroPython configuration available. However, these flags are
-# needed to extract all qstrings
-QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM -DN_XTENSA
QSTR_GEN_EXTRA_CFLAGS += -I$(BUILD)/tmp
vpath %.c . $(TOP)
@@ -75,9 +73,13 @@ $(BUILD)/%.pp: %.c
# to get built before we try to compile any of them.
$(OBJ): | $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/mpversion.h
-$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) | $(HEADER_BUILD)/mpversion.h
+# The logic for qstr regeneration is:
+# - if anything in QSTR_GLOBAL_DEPENDENCIES is newer, then process all source files ($^)
+# - else, if list of newer prerequisites ($?) is not empty, then process just these ($?)
+# - else, process all source files ($^) [this covers "make -B" which can set $? to empty]
+$(HEADER_BUILD)/qstr.i.last: $(SRC_QSTR) $(QSTR_GLOBAL_DEPENDENCIES) | $(HEADER_BUILD)/mpversion.h
$(ECHO) "GEN $@"
- $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $?,$?,$^) >$(HEADER_BUILD)/qstr.i.last;
+ $(Q)$(CPP) $(QSTR_GEN_EXTRA_CFLAGS) $(CFLAGS) $(if $(filter $?,$(QSTR_GLOBAL_DEPENDENCIES)),$^,$(if $?,$?,$^)) >$(HEADER_BUILD)/qstr.i.last;
$(HEADER_BUILD)/qstr.split: $(HEADER_BUILD)/qstr.i.last
$(STEPECHO) "GEN $@"
@@ -130,7 +132,7 @@ xargs -n1 "$(abspath $(MPY_CROSS))" $(MPY_CROSS_FLAGS)
# if the default will not work (mpz is the default).
$(BUILD)/frozen_mpy.c: $(BUILD)/frozen_mpy $(BUILD)/genhdr/qstrdefs.generated.h
$(STEPECHO) "Creating $@"
- $(Q)$(PYTHON) $(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
+ $(Q)$(MPY_TOOL) $(MPY_TOOL_LONGINT_IMPL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(shell $(FIND) -L $(BUILD)/frozen_mpy -type f -name '*.mpy') > $@
endif
ifneq ($(PROG),)
@@ -171,6 +173,27 @@ clean:
$(RM) -rf $(BUILD) $(CLEAN_EXTRA)
.PHONY: clean
+# Clean every non-git file from FROZEN_DIR/FROZEN_MPY_DIR, but making a backup.
+# We run rmdir below to avoid empty backup dir (it will silently fail if backup
+# is non-empty).
+clean-frozen:
+ if [ -n "$(FROZEN_MPY_DIR)" ]; then \
+ backup_dir=$(FROZEN_MPY_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
+ cd $(FROZEN_MPY_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
+ | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
+ rmdir ../$$backup_dir 2>/dev/null || true; \
+ git clean -d -f .; \
+ fi
+
+ if [ -n "$(FROZEN_DIR)" ]; then \
+ backup_dir=$(FROZEN_DIR).$$(date +%Y%m%dT%H%M%S); mkdir $$backup_dir; \
+ cd $(FROZEN_DIR); git status --ignored -u all -s . | awk ' {print $$2}' \
+ | xargs --no-run-if-empty cp --parents -t ../$$backup_dir; \
+ rmdir ../$$backup_dir 2>/dev/null || true; \
+ git clean -d -f .; \
+ fi
+.PHONY: clean-frozen
+
print-cfg:
$(ECHO) "PY_SRC = $(PY_SRC)"
$(ECHO) "BUILD = $(BUILD)"
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index cea87b181..eb1a17204 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -137,7 +137,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_callable_obj, mp_builtin_callable);
STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
#if MICROPY_PY_BUILTINS_STR_UNICODE
mp_uint_t c = mp_obj_get_int(o_in);
- char str[4];
+ uint8_t str[4];
int len = 0;
if (c < 0x80) {
*str = c; len = 1;
@@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
} else {
mp_raise_ValueError("chr() arg not in range(0x110000)");
}
- return mp_obj_new_str(str, len, true);
+ return mp_obj_new_str_via_qstr((char*)str, len);
#else
mp_int_t ord = mp_obj_get_int(o_in);
if (0 <= ord && ord <= 0xff) {
- char str[1] = {ord};
- return mp_obj_new_str(str, 1, true);
+ uint8_t str[1] = {ord};
+ return mp_obj_new_str_via_qstr((char*)str, 1);
} else {
mp_raise_ValueError("chr() arg not in range(256)");
}
@@ -173,46 +173,31 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_chr_obj, mp_builtin_chr);
STATIC mp_obj_t mp_builtin_dir(size_t n_args, const mp_obj_t *args) {
- // TODO make this function more general and less of a hack
-
- mp_obj_dict_t *dict = NULL;
- mp_map_t *members = NULL;
- if (n_args == 0) {
- // make a list of names in the local name space
- dict = mp_locals_get();
- } else { // n_args == 1
- // make a list of names in the given object
- if (MP_OBJ_IS_TYPE(args[0], &mp_type_module)) {
- dict = mp_obj_module_get_globals(args[0]);
- } else {
- mp_obj_type_t *type;
- if (MP_OBJ_IS_TYPE(args[0], &mp_type_type)) {
- type = MP_OBJ_TO_PTR(args[0]);
- } else {
- type = mp_obj_get_type(args[0]);
- }
- if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) {
- dict = type->locals_dict;
- }
- }
- if (mp_obj_is_instance_type(mp_obj_get_type(args[0]))) {
- mp_obj_instance_t *inst = MP_OBJ_TO_PTR(args[0]);
- members = &inst->members;
- }
- }
-
mp_obj_t dir = mp_obj_new_list(0, NULL);
- if (dict != NULL) {
+ if (n_args == 0) {
+ // Make a list of names in the local namespace
+ mp_obj_dict_t *dict = mp_locals_get();
for (size_t i = 0; i < dict->map.alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
mp_obj_list_append(dir, dict->map.table[i].key);
}
}
- }
- if (members != NULL) {
- for (size_t i = 0; i < members->alloc; i++) {
- if (MP_MAP_SLOT_IS_FILLED(members, i)) {
- mp_obj_list_append(dir, members->table[i].key);
+ } else { // n_args == 1
+ // Make a list of names in the given object
+ // Implemented by probing all possible qstrs with mp_load_method_maybe
+ size_t nqstr = QSTR_TOTAL();
+ for (size_t i = MP_QSTR_ + 1; i < nqstr; ++i) {
+ mp_obj_t dest[2];
+ mp_load_method_protected(args[0], i, dest, false);
+ if (dest[0] != MP_OBJ_NULL) {
+ #if MICROPY_PY_ALL_SPECIAL_METHODS
+ // Support for __dir__: see if we can dispatch to this special method
+ // This relies on MP_QSTR__dir__ being first after MP_QSTR_
+ if (i == MP_QSTR___dir__ && dest[1] != MP_OBJ_NULL) {
+ return mp_call_method_n_kw(0, 0, dest);
+ }
+ #endif
+ mp_obj_list_append(dir, MP_OBJ_NEW_QSTR(i));
}
}
}
@@ -343,19 +328,19 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct);
STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
size_t len;
- const char *str = mp_obj_str_get_data(o_in, &len);
+ const byte *str = (const byte*)mp_obj_str_get_data(o_in, &len);
#if MICROPY_PY_BUILTINS_STR_UNICODE
if (MP_OBJ_IS_STR(o_in)) {
- len = unichar_charlen(str, len);
+ len = utf8_charlen(str, len);
if (len == 1) {
- return mp_obj_new_int(utf8_get_char((const byte*)str));
+ return mp_obj_new_int(utf8_get_char(str));
}
} else
#endif
{
// a bytes object, or a str without unicode support (don't sign extend the char)
if (len == 1) {
- return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]);
+ return MP_OBJ_NEW_SMALL_INT(str[0]);
}
}
@@ -383,46 +368,52 @@ STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj, 2, 3, mp_builtin_pow);
-STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
- mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP);
- mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP);
- const char *sep_data = " ";
- size_t sep_len = 1;
- const char *end_data = "\n";
- size_t end_len = 1;
- if (sep_elem != NULL && sep_elem->value != mp_const_none) {
- sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len);
- }
- if (end_elem != NULL && end_elem->value != mp_const_none) {
- end_data = mp_obj_str_get_data(end_elem->value, &end_len);
- }
- #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
- void *stream_obj = &mp_sys_stdout_obj;
- mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP);
- if (file_elem != NULL && file_elem->value != mp_const_none) {
- stream_obj = MP_OBJ_TO_PTR(file_elem->value); // XXX may not be a concrete object
- }
+STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sep, ARG_end, ARG_file };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__space_)} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR__0x0a_)} },
+ #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
+ { MP_QSTR_file, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_sys_stdout_obj)} },
+ #endif
+ };
+
+ // parse args (a union is used to reduce the amount of C stack that is needed)
+ union {
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ size_t len[2];
+ } u;
+ mp_arg_parse_all(0, NULL, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, u.args);
- mp_print_t print = {stream_obj, mp_stream_write_adaptor};
+ #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
+ mp_get_stream_raise(u.args[ARG_file].u_obj, MP_STREAM_OP_WRITE);
+ mp_print_t print = {MP_OBJ_TO_PTR(u.args[ARG_file].u_obj), mp_stream_write_adaptor};
#endif
+
+ // extract the objects first because we are going to use the other part of the union
+ mp_obj_t sep = u.args[ARG_sep].u_obj;
+ mp_obj_t end = u.args[ARG_end].u_obj;
+ const char *sep_data = mp_obj_str_get_data(sep, &u.len[0]);
+ const char *end_data = mp_obj_str_get_data(end, &u.len[1]);
+
for (size_t i = 0; i < n_args; i++) {
if (i > 0) {
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
- mp_stream_write_adaptor(stream_obj, sep_data, sep_len);
+ mp_stream_write_adaptor(print.data, sep_data, u.len[0]);
#else
- mp_print_strn(&mp_plat_print, sep_data, sep_len, 0, 0, 0);
+ mp_print_strn(&mp_plat_print, sep_data, u.len[0], 0, 0, 0);
#endif
}
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
- mp_obj_print_helper(&print, args[i], PRINT_STR);
+ mp_obj_print_helper(&print, pos_args[i], PRINT_STR);
#else
- mp_obj_print_helper(&mp_plat_print, args[i], PRINT_STR);
+ mp_obj_print_helper(&mp_plat_print, pos_args[i], PRINT_STR);
#endif
}
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
- mp_stream_write_adaptor(stream_obj, end_data, end_len);
+ mp_stream_write_adaptor(print.data, end_data, u.len[1]);
#else
- mp_print_strn(&mp_plat_print, end_data, end_len, 0, 0, 0);
+ mp_print_strn(&mp_plat_print, end_data, u.len[1], 0, 0, 0);
#endif
return mp_const_none;
}
@@ -454,19 +445,46 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);
STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) {
mp_obj_t o_in = args[0];
if (MP_OBJ_IS_INT(o_in)) {
- return o_in;
+ if (n_args <= 1) {
+ return o_in;
+ }
+
+ #if !MICROPY_PY_BUILTINS_ROUND_INT
+ mp_raise_NotImplementedError(NULL);
+ #else
+ mp_int_t num_dig = mp_obj_get_int(args[1]);
+ if (num_dig >= 0) {
+ return o_in;
+ }
+
+ mp_obj_t mult = mp_binary_op(MP_BINARY_OP_POWER, MP_OBJ_NEW_SMALL_INT(10), MP_OBJ_NEW_SMALL_INT(-num_dig));
+ mp_obj_t half_mult = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, mult, MP_OBJ_NEW_SMALL_INT(2));
+ mp_obj_t modulo = mp_binary_op(MP_BINARY_OP_MODULO, o_in, mult);
+ mp_obj_t rounded = mp_binary_op(MP_BINARY_OP_SUBTRACT, o_in, modulo);
+ if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, half_mult, modulo))) {
+ return rounded;
+ } else if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_MORE, modulo, half_mult))) {
+ return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult);
+ } else {
+ // round to even number
+ mp_obj_t floor = mp_binary_op(MP_BINARY_OP_FLOOR_DIVIDE, o_in, mult);
+ if (mp_obj_is_true(mp_binary_op(MP_BINARY_OP_AND, floor, MP_OBJ_NEW_SMALL_INT(1)))) {
+ return mp_binary_op(MP_BINARY_OP_ADD, rounded, mult);
+ } else {
+ return rounded;
+ }
+ }
+ #endif
}
#if MICROPY_PY_BUILTINS_FLOAT
- mp_int_t num_dig = 0;
+ mp_float_t val = mp_obj_get_float(o_in);
if (n_args > 1) {
- num_dig = mp_obj_get_int(args[1]);
- mp_float_t val = mp_obj_get_float(o_in);
+ mp_int_t num_dig = mp_obj_get_int(args[1]);
mp_float_t mult = MICROPY_FLOAT_C_FUN(pow)(10, num_dig);
// TODO may lead to overflow
mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val * mult) / mult;
return mp_obj_new_float(rounded);
}
- mp_float_t val = mp_obj_get_float(o_in);
mp_float_t rounded = MICROPY_FLOAT_C_FUN(nearbyint)(val);
return mp_obj_new_int_from_float(rounded);
#else
@@ -543,14 +561,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr);
STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) {
qstr attr = mp_obj_str_get_qstr(attr_in);
-
mp_obj_t dest[2];
- // TODO: https://docs.python.org/3/library/functions.html?highlight=hasattr#hasattr
- // explicitly says "This is implemented by calling getattr(object, name) and seeing
- // whether it raises an AttributeError or not.", so we should explicitly wrap this
- // in nlr_push and handle exception.
- mp_load_method_maybe(object_in, attr, dest);
-
+ mp_load_method_protected(object_in, attr, dest, false);
return mp_obj_new_bool(dest[0] != MP_OBJ_NULL);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj, mp_builtin_hasattr);
diff --git a/py/modcollections.c b/py/modcollections.c
index 837ec2f92..91e735528 100644
--- a/py/modcollections.c
+++ b/py/modcollections.c
@@ -30,6 +30,9 @@
STATIC const mp_rom_map_elem_t mp_module_collections_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_collections) },
+ #if MICROPY_PY_COLLECTIONS_DEQUE
+ { MP_ROM_QSTR(MP_QSTR_deque), MP_ROM_PTR(&mp_type_deque) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_namedtuple), MP_ROM_PTR(&mp_namedtuple_obj) },
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
{ MP_ROM_QSTR(MP_QSTR_OrderedDict), MP_ROM_PTR(&mp_type_ordereddict) },
diff --git a/py/modio.c b/py/modio.c
index 9263b5949..9b09de96e 100644
--- a/py/modio.c
+++ b/py/modio.c
@@ -30,6 +30,8 @@
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/stream.h"
+#include "py/binary.h"
+#include "py/objarray.h"
#include "py/objstringio.h"
#include "py/frozenmod.h"
@@ -38,6 +40,70 @@
extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
+#if MICROPY_PY_IO_IOBASE
+
+STATIC const mp_obj_type_t mp_type_iobase;
+
+STATIC mp_obj_base_t iobase_singleton = {&mp_type_iobase};
+
+STATIC mp_obj_t iobase_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ (void)type;
+ (void)n_args;
+ (void)n_kw;
+ (void)args;
+ return MP_OBJ_FROM_PTR(&iobase_singleton);
+}
+
+STATIC mp_uint_t iobase_read_write(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode, qstr qst) {
+ mp_obj_t dest[3];
+ mp_load_method(obj, qst, dest);
+ mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, size, buf};
+ dest[2] = MP_OBJ_FROM_PTR(&ar);
+ mp_obj_t ret = mp_call_method_n_kw(1, 0, dest);
+ if (ret == mp_const_none) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ } else {
+ return mp_obj_get_int(ret);
+ }
+}
+STATIC mp_uint_t iobase_read(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode) {
+ return iobase_read_write(obj, buf, size, errcode, MP_QSTR_readinto);
+}
+
+STATIC mp_uint_t iobase_write(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode) {
+ return iobase_read_write(obj, (void*)buf, size, errcode, MP_QSTR_write);
+}
+
+STATIC mp_uint_t iobase_ioctl(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_t dest[4];
+ mp_load_method(obj, MP_QSTR_ioctl, dest);
+ dest[2] = mp_obj_new_int_from_uint(request);
+ dest[3] = mp_obj_new_int_from_uint(arg);
+ mp_int_t ret = mp_obj_get_int(mp_call_method_n_kw(2, 0, dest));
+ if (ret >= 0) {
+ return ret;
+ } else {
+ *errcode = -ret;
+ return MP_STREAM_ERROR;
+ }
+}
+
+STATIC const mp_stream_p_t iobase_p = {
+ .read = iobase_read,
+ .write = iobase_write,
+ .ioctl = iobase_ioctl,
+};
+
+STATIC const mp_obj_type_t mp_type_iobase = {
+ { &mp_type_type },
+ .name = MP_QSTR_IOBase,
+ .make_new = iobase_make_new,
+ .protocol = &iobase_p,
+};
+
+#endif // MICROPY_PY_IO_IOBASE
+
#if MICROPY_PY_IO_BUFFEREDWRITER
typedef struct _mp_obj_bufwriter_t {
mp_obj_base_t base;
@@ -131,7 +197,7 @@ STATIC const mp_obj_type_t bufwriter_type = {
};
#endif // MICROPY_PY_IO_BUFFEREDWRITER
-#if MICROPY_MODULE_FROZEN_STR
+#if MICROPY_PY_IO_RESOURCE_STREAM
STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
VSTR_FIXED(path_buf, MICROPY_ALLOC_PATH_MAX);
size_t len;
@@ -176,10 +242,10 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) {
return MP_OBJ_FROM_PTR(o);
}
- mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false);
+ mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len);
return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map);
}
-MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream);
#endif
STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
@@ -187,6 +253,9 @@ STATIC const mp_rom_map_elem_t mp_module_io_globals_table[] = {
// Note: mp_builtin_open_obj should be defined by port, it's not
// part of the core.
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
+ #if MICROPY_PY_IO_IOBASE
+ { MP_ROM_QSTR(MP_QSTR_IOBase), MP_ROM_PTR(&mp_type_iobase) },
+ #endif
#if MICROPY_PY_IO_RESOURCE_STREAM
{ MP_ROM_QSTR(MP_QSTR_resource_stream), MP_ROM_PTR(&resource_stream_obj) },
#endif
diff --git a/py/modmicropython.c b/py/modmicropython.c
index 2aac53adc..864d1a5c5 100644
--- a/py/modmicropython.c
+++ b/py/modmicropython.c
@@ -35,6 +35,7 @@
// Various builtins specific to MicroPython runtime,
// living in micropython module
+#if MICROPY_ENABLE_COMPILER
STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value));
@@ -44,6 +45,7 @@ STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) {
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level);
+#endif
#if MICROPY_PY_MICROPYTHON_MEM_INFO
@@ -103,14 +105,21 @@ STATIC mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, mp_micropython_qstr_info);
-#if MICROPY_STACK_CHECK
+#endif // MICROPY_PY_MICROPYTHON_MEM_INFO
+
+#if MICROPY_PY_MICROPYTHON_STACK_USE
STATIC mp_obj_t mp_micropython_stack_use(void) {
return MP_OBJ_NEW_SMALL_INT(mp_stack_usage());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use);
#endif
-#endif // MICROPY_PY_MICROPYTHON_MEM_INFO
+#if MICROPY_ENABLE_PYSTACK
+STATIC mp_obj_t mp_micropython_pystack_use(void) {
+ return MP_OBJ_NEW_SMALL_INT(mp_pystack_usage());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_pystack_use_obj, mp_micropython_pystack_use);
+#endif
#if MICROPY_ENABLE_GC
STATIC mp_obj_t mp_micropython_heap_lock(void) {
@@ -151,7 +160,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_micropython_schedule_obj, mp_micropython_sch
STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) },
{ MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) },
+ #if MICROPY_ENABLE_COMPILER
{ MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) },
+ #endif
#if MICROPY_PY_MICROPYTHON_MEM_INFO
#if MICROPY_MEM_STATS
{ MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) },
@@ -160,13 +171,16 @@ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = {
#endif
{ MP_ROM_QSTR(MP_QSTR_mem_info), MP_ROM_PTR(&mp_micropython_mem_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_qstr_info), MP_ROM_PTR(&mp_micropython_qstr_info_obj) },
- #if MICROPY_STACK_CHECK
+#endif
+ #if MICROPY_PY_MICROPYTHON_STACK_USE
{ MP_ROM_QSTR(MP_QSTR_stack_use), MP_ROM_PTR(&mp_micropython_stack_use_obj) },
#endif
-#endif
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && (MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0)
{ MP_ROM_QSTR(MP_QSTR_alloc_emergency_exception_buf), MP_ROM_PTR(&mp_alloc_emergency_exception_buf_obj) },
#endif
+ #if MICROPY_ENABLE_PYSTACK
+ { MP_ROM_QSTR(MP_QSTR_pystack_use), MP_ROM_PTR(&mp_micropython_pystack_use_obj) },
+ #endif
#if MICROPY_ENABLE_GC
{ MP_ROM_QSTR(MP_QSTR_heap_lock), MP_ROM_PTR(&mp_micropython_heap_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_heap_unlock), MP_ROM_PTR(&mp_micropython_heap_unlock_obj) },
diff --git a/py/modsys.c b/py/modsys.c
index de3cb7e1f..e32841923 100644
--- a/py/modsys.c
+++ b/py/modsys.c
@@ -106,7 +106,8 @@ STATIC mp_obj_t mp_sys_print_exception(size_t n_args, const mp_obj_t *args) {
#if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
void *stream_obj = &mp_sys_stdout_obj;
if (n_args > 1) {
- stream_obj = MP_OBJ_TO_PTR(args[1]); // XXX may fail
+ mp_get_stream_raise(args[1], MP_STREAM_OP_WRITE);
+ stream_obj = MP_OBJ_TO_PTR(args[1]);
}
mp_print_t print = {stream_obj, mp_stream_write_adaptor};
@@ -140,10 +141,12 @@ STATIC mp_obj_t mp_sys_exc_info(void) {
MP_DEFINE_CONST_FUN_OBJ_0(mp_sys_exc_info_obj, mp_sys_exc_info);
#endif
+#if MICROPY_PY_SYS_GETSIZEOF
STATIC mp_obj_t mp_sys_getsizeof(mp_obj_t obj) {
return mp_unary_op(MP_UNARY_OP_SIZEOF, obj);
}
-MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_sys_getsizeof_obj, mp_sys_getsizeof);
+#endif
STATIC const mp_rom_map_elem_t mp_module_sys_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys) },
diff --git a/py/modthread.c b/py/modthread.c
index cb071d0f8..61ada5035 100644
--- a/py/modthread.c
+++ b/py/modthread.c
@@ -165,6 +165,12 @@ STATIC void *thread_entry(void *args_in) {
mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan
mp_stack_set_limit(args->stack_size);
+ #if MICROPY_ENABLE_PYSTACK
+ // TODO threading and pystack is not fully supported, for now just make a small stack
+ mp_obj_t mini_pystack[128];
+ mp_pystack_init(mini_pystack, &mini_pystack[128]);
+ #endif
+
// set locals and globals from the calling context
mp_locals_set(args->dict_locals);
mp_globals_set(args->dict_globals);
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 74d7c2c92..52a7c05a2 100755
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -79,7 +79,7 @@
// - seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 64-bit fp, e != 0x7ff
// - s1111111 11110000 00000000 00000000 00000000 00000000 00000000 00000000 +/- inf
// - 01111111 11111000 00000000 00000000 00000000 00000000 00000000 00000000 normalised nan
-// - 01111111 11111101 00000000 00000000 iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int
+// - 01111111 11111101 iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiiii iiiiiii1 small int
// - 01111111 11111110 00000000 00000000 qqqqqqqq qqqqqqqq qqqqqqqq qqqqqqq1 str
// - 01111111 11111100 00000000 00000000 pppppppp pppppppp pppppppp pppppp00 ptr (4 byte alignment)
// Stored as O = R + 0x8004000000000000, retrieved as R = O - 0x8004000000000000.
@@ -353,7 +353,7 @@
#endif
// Whether to enable optimisation of: a, b, c = d, e, f
-// Cost 156 bytes (Thumb2)
+// Requires MICROPY_COMP_DOUBLE_TUPLE_ASSIGN and costs 68 bytes (Thumb2)
#ifndef MICROPY_COMP_TRIPLE_TUPLE_ASSIGN
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (0)
#endif
@@ -411,6 +411,13 @@
/*****************************************************************************/
/* Python internal features */
+// Whether to enable import of external modules
+// When disabled, only importing of built-in modules is supported
+// When enabled, a port must implement mp_import_stat (among other things)
+#ifndef MICROPY_ENABLE_EXTERNAL_IMPORT
+#define MICROPY_ENABLE_EXTERNAL_IMPORT (1)
+#endif
+
// Whether to use the POSIX reader for importing files
#ifndef MICROPY_READER_POSIX
#define MICROPY_READER_POSIX (0)
@@ -452,6 +459,17 @@
#define MICROPY_ENABLE_FINALISER (0)
#endif
+// Whether to enable a separate allocator for the Python stack.
+// If enabled then the code must call mp_pystack_init before mp_init.
+#ifndef MICROPY_ENABLE_PYSTACK
+#define MICROPY_ENABLE_PYSTACK (0)
+#endif
+
+// Number of bytes that memory returned by mp_pystack_alloc will be aligned by.
+#ifndef MICROPY_PYSTACK_ALIGN
+#define MICROPY_PYSTACK_ALIGN (8)
+#endif
+
// Whether to check C stack usage. C stack used for calling Python functions,
// etc. Not checking means segfault on overflow.
#ifndef MICROPY_STACK_CHECK
@@ -679,22 +697,41 @@ typedef double mp_float_t;
#define MICROPY_VFS (0)
#endif
+// Support for VFS POSIX component, to mount a POSIX filesystem within VFS
+#ifndef MICROPY_VFS
+#define MICROPY_VFS_POSIX (0)
+#endif
+
+// Support for VFS FAT component, to mount a FAT filesystem within VFS
+#ifndef MICROPY_VFS
+#define MICROPY_VFS_FAT (0)
+#endif
+
/*****************************************************************************/
/* Fine control over Python builtins, classes, modules, etc */
+// Whether to support multiple inheritance of Python classes. Multiple
+// inheritance makes some C functions inherently recursive, and adds a bit of
+// code overhead.
+#ifndef MICROPY_MULTIPLE_INHERITANCE
+#define MICROPY_MULTIPLE_INHERITANCE (1)
+#endif
+
// Whether to implement attributes on functions
#ifndef MICROPY_PY_FUNCTION_ATTRS
#define MICROPY_PY_FUNCTION_ATTRS (0)
#endif
-// Whether to support descriptors (__get__ and __set__)
-// This costs some code size and makes all load attrs and store attrs slow
+// Whether to support the descriptors __get__, __set__, __delete__
+// This costs some code size and makes load/store/delete of instance
+// attributes slower for the classes that use this feature
#ifndef MICROPY_PY_DESCRIPTORS
#define MICROPY_PY_DESCRIPTORS (0)
#endif
// Whether to support class __delattr__ and __setattr__ methods
-// This costs some code size and makes all del attrs and store attrs slow
+// This costs some code size and makes store/delete of instance
+// attributes slower for the classes that use this feature
#ifndef MICROPY_PY_DELATTR_SETATTR
#define MICROPY_PY_DELATTR_SETATTR (0)
#endif
@@ -704,6 +741,15 @@ typedef double mp_float_t;
#define MICROPY_PY_ASYNC_AWAIT (1)
#endif
+// Non-standard .pend_throw() method for generators, allowing for
+// Future-like behavior with respect to exception handling: an
+// exception set with .pend_throw() will activate on the next call
+// to generator's .send() or .__next__(). (This is useful to implement
+// async schedulers.)
+#ifndef MICROPY_PY_GENERATOR_PEND_THROW
+#define MICROPY_PY_GENERATOR_PEND_THROW (1)
+#endif
+
// Issue a warning when comparing str and bytes objects
#ifndef MICROPY_PY_STR_BYTES_CMP_WARN
#define MICROPY_PY_STR_BYTES_CMP_WARN (0)
@@ -776,6 +822,19 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_RANGE_ATTRS (1)
#endif
+// Whether to support binary ops [only (in)equality is defined] between range
+// objects. With this option disabled all range objects that are not exactly
+// the same object will compare as not-equal. With it enabled the semantics
+// match CPython and ranges are equal if they yield the same sequence of items.
+#ifndef MICROPY_PY_BUILTINS_RANGE_BINOP
+#define MICROPY_PY_BUILTINS_RANGE_BINOP (0)
+#endif
+
+// Whether to support rounding of integers (incl bignum); eg round(123,-1)=120
+#ifndef MICROPY_PY_BUILTINS_ROUND_INT
+#define MICROPY_PY_BUILTINS_ROUND_INT (0)
+#endif
+
// Whether to support timeout exceptions (like socket.timeout)
#ifndef MICROPY_PY_BUILTINS_TIMEOUTERROR
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0)
@@ -881,6 +940,11 @@ typedef double mp_float_t;
#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
#endif
+// Whether to provide "micropython.stack_use" function
+#ifndef MICROPY_PY_MICROPYTHON_STACK_USE
+#define MICROPY_PY_MICROPYTHON_STACK_USE (MICROPY_PY_MICROPYTHON_MEM_INFO)
+#endif
+
// Whether to provide "array" module. Note that large chunk of the
// underlying code is shared with "bytearray" builtin type, so to
// get real savings, it should be disabled too.
@@ -911,11 +975,21 @@ typedef double mp_float_t;
#define MICROPY_PY_COLLECTIONS (1)
#endif
+// Whether to provide "ucollections.deque" type
+#ifndef MICROPY_PY_COLLECTIONS_DEQUE
+#define MICROPY_PY_COLLECTIONS_DEQUE (0)
+#endif
+
// Whether to provide "collections.OrderedDict" type
#ifndef MICROPY_PY_COLLECTIONS_ORDEREDDICT
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (0)
#endif
+// Whether to provide the _asdict function for namedtuple
+#ifndef MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT
+#define MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT (0)
+#endif
+
// Whether to provide "math" module
#ifndef MICROPY_PY_MATH
#define MICROPY_PY_MATH (1)
@@ -946,9 +1020,18 @@ typedef double mp_float_t;
#define MICROPY_PY_IO (1)
#endif
+// Whether to provide "io.IOBase" class to support user streams
+#ifndef MICROPY_PY_IO_IOBASE
+#define MICROPY_PY_IO_IOBASE (0)
+#endif
+
// Whether to provide "uio.resource_stream()" function with
// the semantics of CPython's pkg_resources.resource_stream()
-// (allows to access resources in frozen packages).
+// (allows to access binary resources in frozen source packages).
+// Note that the same functionality can be achieved in "pure
+// Python" by prepocessing binary resources into Python source
+// and bytecode-freezing it (with a simple helper module available
+// e.g. in micropython-lib).
#ifndef MICROPY_PY_IO_RESOURCE_STREAM
#define MICROPY_PY_IO_RESOURCE_STREAM (0)
#endif
@@ -1094,6 +1177,14 @@ typedef double mp_float_t;
#define MICROPY_PY_UHASHLIB (0)
#endif
+#ifndef MICROPY_PY_UHASHLIB_SHA1
+#define MICROPY_PY_UHASHLIB_SHA1 (0)
+#endif
+
+#ifndef MICROPY_PY_UHASHLIB_SHA256
+#define MICROPY_PY_UHASHLIB_SHA256 (1)
+#endif
+
#ifndef MICROPY_PY_UBINASCII
#define MICROPY_PY_UBINASCII (0)
#endif
@@ -1217,29 +1308,26 @@ typedef double mp_float_t;
#elif defined(MP_ENDIANNESS_BIG)
#define MP_ENDIANNESS_LITTLE (!MP_ENDIANNESS_BIG)
#else
- // Endiannes not defined by port so try to autodetect it.
+ // Endianness not defined by port so try to autodetect it.
#if defined(__BYTE_ORDER__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define MP_ENDIANNESS_LITTLE (1)
- #else
+ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define MP_ENDIANNESS_LITTLE (0)
#endif
- #elif defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN)
- #define MP_ENDIANNESS_LITTLE (1)
- #elif defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined (_BIG_ENDIAN)
- #define MP_ENDIANNESS_LITTLE (0)
#else
#include <endian.h>
#if defined(__BYTE_ORDER)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define MP_ENDIANNESS_LITTLE (1)
- #else
+ #elif __BYTE_ORDER == __BIG_ENDIAN
#define MP_ENDIANNESS_LITTLE (0)
#endif
- #else
- #error endianness not defined and cannot detect it
#endif
#endif
+ #ifndef MP_ENDIANNESS_LITTLE
+ #error endianness not defined and cannot detect it
+ #endif
#define MP_ENDIANNESS_BIG (!MP_ENDIANNESS_LITTLE)
#endif
@@ -1315,4 +1403,24 @@ typedef double mp_float_t;
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
#endif
+#ifndef MP_HTOBE16
+#if MP_ENDIANNESS_LITTLE
+# define MP_HTOBE16(x) ((uint16_t)( (((x) & 0xff) << 8) | (((x) >> 8) & 0xff) ))
+# define MP_BE16TOH(x) MP_HTOBE16(x)
+#else
+# define MP_HTOBE16(x) (x)
+# define MP_BE16TOH(x) (x)
+#endif
+#endif
+
+#ifndef MP_HTOBE32
+#if MP_ENDIANNESS_LITTLE
+# define MP_HTOBE32(x) ((uint32_t)( (((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff) ))
+# define MP_BE32TOH(x) MP_HTOBE32(x)
+#else
+# define MP_HTOBE32(x) (x)
+# define MP_BE32TOH(x) (x)
+#endif
+#endif
+
#endif // MICROPY_INCLUDED_PY_MPCONFIG_H
diff --git a/py/mperrno.h b/py/mperrno.h
index a028157ba..1eb342bc3 100644
--- a/py/mperrno.h
+++ b/py/mperrno.h
@@ -125,7 +125,7 @@
#define MP_EPIPE EPIPE
#define MP_EDOM EDOM
#define MP_ERANGE ERANGE
-#define MP_EWOULDBLOCK EAGAIN
+#define MP_EWOULDBLOCK EWOULDBLOCK
#define MP_EOPNOTSUPP EOPNOTSUPP
#define MP_EAFNOSUPPORT EAFNOSUPPORT
#define MP_EADDRINUSE EADDRINUSE
diff --git a/py/mpprint.c b/py/mpprint.c
index a569ef793..c2e65301c 100644
--- a/py/mpprint.c
+++ b/py/mpprint.c
@@ -446,11 +446,16 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
}
}
- // parse long specifiers (current not used)
- //bool long_arg = false;
+ // parse long specifiers (only for LP64 model where they make a difference)
+ #ifndef __LP64__
+ const
+ #endif
+ bool long_arg = false;
if (*fmt == 'l') {
++fmt;
- //long_arg = true;
+ #ifdef __LP64__
+ long_arg = true;
+ #endif
}
if (*fmt == '\0') {
@@ -505,14 +510,21 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) {
chrs += mp_print_int(print, va_arg(args, int), 1, 10, 'a', flags, fill, width);
break;
case 'x':
- chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width);
- break;
- case 'X':
- chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'A', flags, fill, width);
+ case 'X': {
+ char fmt_c = *fmt - 'X' + 'A';
+ mp_uint_t val;
+ if (long_arg) {
+ val = va_arg(args, unsigned long int);
+ } else {
+ val = va_arg(args, unsigned int);
+ }
+ chrs += mp_print_int(print, val, 0, 16, fmt_c, flags, fill, width);
break;
+ }
case 'p':
case 'P': // don't bother to handle upcase for 'P'
- chrs += mp_print_int(print, va_arg(args, unsigned int), 0, 16, 'a', flags, fill, width);
+ // Use unsigned long int to work on both ILP32 and LP64 systems
+ chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width);
break;
#if MICROPY_PY_BUILTINS_FLOAT
case 'e':
diff --git a/py/mpstate.h b/py/mpstate.h
index c50947066..6e68159ee 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -80,7 +80,6 @@ typedef struct _mp_state_mem_t {
int gc_stack_overflow;
size_t gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
- size_t *gc_sp;
uint16_t gc_lock_depth;
// This variable controls auto garbage collection. If set to false then the
@@ -109,10 +108,11 @@ typedef struct _mp_state_mem_t {
// This structure hold runtime and VM information. It includes a section
// which contains root pointers that must be scanned by the GC.
typedef struct _mp_state_vm_t {
- ////////////////////////////////////////////////////////////
- // START ROOT POINTER SECTION
- // everything that needs GC scanning must go here
- // this must start at the start of this structure
+ //
+ // CONTINUE ROOT POINTER SECTION
+ // This must start at the start of this structure and follows
+ // the state in the mp_state_thread_t structure, continuing
+ // the root pointer section from there.
//
qstr_pool_t *last_pool;
@@ -146,8 +146,6 @@ typedef struct _mp_state_vm_t {
volatile mp_obj_t mp_pending_exception;
#if MICROPY_ENABLE_SCHEDULER
- volatile int16_t sched_state;
- uint16_t sched_sp;
mp_sched_item_t sched_stack[MICROPY_SCHEDULER_DEPTH];
#endif
@@ -173,12 +171,15 @@ typedef struct _mp_state_vm_t {
// root pointers for extmod
- #ifdef MICROPY_PY_OS_DUPTERM
+ #if MICROPY_REPL_EVENT_DRIVEN
+ vstr_t *repl_line;
+ #endif
+
+ #if MICROPY_PY_OS_DUPTERM
mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM];
- mp_obj_t dupterm_arr_obj;
#endif
- #ifdef MICROPY_PY_LWIP_SLIP
+ #if MICROPY_PY_LWIP_SLIP
mp_obj_t lwip_slip_stream;
#endif
@@ -202,13 +203,20 @@ typedef struct _mp_state_vm_t {
mp_thread_mutex_t qstr_mutex;
#endif
+ #if MICROPY_ENABLE_COMPILER
mp_uint_t mp_optimise_value;
+ #endif
// size of the emergency exception buf, if it's dynamically allocated
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF && MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE == 0
mp_int_t mp_emergency_exception_buf_size;
#endif
+ #if MICROPY_ENABLE_SCHEDULER
+ volatile int16_t sched_state;
+ uint16_t sched_sp;
+ #endif
+
#if MICROPY_PY_THREAD_GIL
// This is a global mutex used to make the VM/runtime thread-safe.
mp_thread_mutex_t gil_mutex;
@@ -218,12 +226,6 @@ typedef struct _mp_state_vm_t {
// This structure holds state that is specific to a given thread.
// Everything in this structure is scanned for root pointers.
typedef struct _mp_state_thread_t {
- mp_obj_dict_t *dict_locals;
- mp_obj_dict_t *dict_globals;
-
- // Note: nlr asm code has the offset of this hard-coded
- nlr_buf_t *nlr_top; // ROOT POINTER
-
// Stack top at the start of program
char *stack_top;
@@ -234,12 +236,27 @@ typedef struct _mp_state_thread_t {
#if MICROPY_STACK_CHECK
size_t stack_limit;
#endif
+
+ #if MICROPY_ENABLE_PYSTACK
+ uint8_t *pystack_start;
+ uint8_t *pystack_end;
+ uint8_t *pystack_cur;
+ #endif
+
+ ////////////////////////////////////////////////////////////
+ // START ROOT POINTER SECTION
+ // Everything that needs GC scanning must start here, and
+ // is followed by state in the mp_state_vm_t structure.
+ //
+
+ mp_obj_dict_t *dict_locals;
+ mp_obj_dict_t *dict_globals;
+
+ nlr_buf_t *nlr_top;
} mp_state_thread_t;
// This structure combines the above 3 structures.
// The order of the entries are important for root pointer scanning in the GC to work.
-// Note: if this structure changes then revisit all nlr asm code since they
-// have the offset of nlr_top hard-coded.
typedef struct _mp_state_ctx_t {
mp_state_thread_t thread;
mp_state_vm_t vm;
diff --git a/py/mpz.c b/py/mpz.c
index d300a8e5d..8687092d0 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -537,83 +537,57 @@ STATIC void mpn_div(mpz_dig_t *num_dig, size_t *num_len, const mpz_dig_t *den_di
// not to overflow the borrow variable. And the shifting of
// borrow needs some special logic (it's a shift right with
// round up).
-
- if (DIG_SIZE < 8 * sizeof(mpz_dbl_dig_t) / 2) {
- const mpz_dig_t *d = den_dig;
- mpz_dbl_dig_t d_norm = 0;
- mpz_dbl_dig_signed_t borrow = 0;
-
- for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
- d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
- borrow += (mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK); // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
- *n = borrow & DIG_MASK;
- borrow >>= DIG_SIZE;
- }
- borrow += *num_dig; // will overflow if DIG_SIZE >= 8*sizeof(mpz_dbl_dig_t)/2
- *num_dig = borrow & DIG_MASK;
- borrow >>= DIG_SIZE;
-
- // adjust quotient if it is too big
- for (; borrow != 0; --quo) {
- d = den_dig;
- d_norm = 0;
- mpz_dbl_dig_t carry = 0;
- for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
- d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
- carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
- *n = carry & DIG_MASK;
- carry >>= DIG_SIZE;
- }
- carry += *num_dig;
- *num_dig = carry & DIG_MASK;
- carry >>= DIG_SIZE;
-
- borrow += carry;
- }
- } else { // DIG_SIZE == 8 * sizeof(mpz_dbl_dig_t) / 2
- const mpz_dig_t *d = den_dig;
- mpz_dbl_dig_t d_norm = 0;
- mpz_dbl_dig_t borrow = 0;
-
- for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
- d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
- mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK);
- if (x >= *n || *n - x <= borrow) {
- borrow += (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)*n;
- *n = (-borrow) & DIG_MASK;
- borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
- } else {
- *n = ((mpz_dbl_dig_t)*n - (mpz_dbl_dig_t)x - (mpz_dbl_dig_t)borrow) & DIG_MASK;
- borrow = 0;
- }
- }
- if (borrow >= *num_dig) {
- borrow -= (mpz_dbl_dig_t)*num_dig;
- *num_dig = (-borrow) & DIG_MASK;
+ //
+ const mpz_dig_t *d = den_dig;
+ mpz_dbl_dig_t d_norm = 0;
+ mpz_dbl_dig_t borrow = 0;
+ for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
+ d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
+ mpz_dbl_dig_t x = (mpz_dbl_dig_t)quo * (d_norm & DIG_MASK);
+ #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2
+ borrow += (mpz_dbl_dig_t)*n - x; // will overflow if DIG_SIZE >= MPZ_DBL_DIG_SIZE/2
+ *n = borrow & DIG_MASK;
+ borrow = (mpz_dbl_dig_signed_t)borrow >> DIG_SIZE;
+ #else // DIG_SIZE == MPZ_DBL_DIG_SIZE / 2
+ if (x >= *n || *n - x <= borrow) {
+ borrow += x - (mpz_dbl_dig_t)*n;
+ *n = (-borrow) & DIG_MASK;
borrow = (borrow >> DIG_SIZE) + ((borrow & DIG_MASK) == 0 ? 0 : 1); // shift-right with round-up
} else {
- *num_dig = (*num_dig - borrow) & DIG_MASK;
+ *n = ((mpz_dbl_dig_t)*n - x - borrow) & DIG_MASK;
borrow = 0;
}
+ #endif
+ }
- // adjust quotient if it is too big
- for (; borrow != 0; --quo) {
- d = den_dig;
- d_norm = 0;
- mpz_dbl_dig_t carry = 0;
- for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
- d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
- carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
- *n = carry & DIG_MASK;
- carry >>= DIG_SIZE;
- }
- carry += (mpz_dbl_dig_t)*num_dig;
- *num_dig = carry & DIG_MASK;
- carry >>= DIG_SIZE;
+ #if DIG_SIZE < MPZ_DBL_DIG_SIZE / 2
+ // Borrow was negative in the above for-loop, make it positive for next if-block.
+ borrow = -borrow;
+ #endif
- //assert(borrow >= carry); // enable this to check the logic
- borrow -= carry;
+ // At this point we have either:
+ //
+ // 1. quo was the correct value and the most-sig-digit of num is exactly
+ // cancelled by borrow (borrow == *num_dig). In this case there is
+ // nothing more to do.
+ //
+ // 2. quo was too large, we subtracted too many den from num, and the
+ // most-sig-digit of num is 1 less than borrow (borrow == *num_dig + 1).
+ // In this case we must reduce quo and add back den to num until the
+ // carry from this operation cancels out the borrow.
+ //
+ borrow -= *num_dig;
+ for (; borrow != 0; --quo) {
+ d = den_dig;
+ d_norm = 0;
+ mpz_dbl_dig_t carry = 0;
+ for (mpz_dig_t *n = num_dig - den_len; n < num_dig; ++n, ++d) {
+ d_norm = ((mpz_dbl_dig_t)*d << norm_shift) | (d_norm >> DIG_SIZE);
+ carry += (mpz_dbl_dig_t)*n + (d_norm & DIG_MASK);
+ *n = carry & DIG_MASK;
+ carry >>= DIG_SIZE;
}
+ borrow -= carry;
}
// store this digit of the quotient
@@ -731,17 +705,14 @@ STATIC void mpz_need_dig(mpz_t *z, size_t need) {
}
STATIC mpz_t *mpz_clone(const mpz_t *src) {
+ assert(src->alloc != 0);
mpz_t *z = m_new_obj(mpz_t);
z->neg = src->neg;
z->fixed_dig = 0;
z->alloc = src->alloc;
z->len = src->len;
- if (src->dig == NULL) {
- z->dig = NULL;
- } else {
- z->dig = m_new(mpz_dig_t, z->alloc);
- memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
- }
+ z->dig = m_new(mpz_dig_t, z->alloc);
+ memcpy(z->dig, src->dig, src->alloc * sizeof(mpz_dig_t));
return z;
}
@@ -1009,6 +980,7 @@ these functions are unused
/* returns abs(z)
*/
mpz_t *mpz_abs(const mpz_t *z) {
+ // TODO: handle case of z->alloc=0
mpz_t *z2 = mpz_clone(z);
z2->neg = 0;
return z2;
@@ -1017,6 +989,7 @@ mpz_t *mpz_abs(const mpz_t *z) {
/* returns -z
*/
mpz_t *mpz_neg(const mpz_t *z) {
+ // TODO: handle case of z->alloc=0
mpz_t *z2 = mpz_clone(z);
z2->neg = 1 - z2->neg;
return z2;
@@ -1390,13 +1363,14 @@ void mpz_pow_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs) {
can have dest, lhs, rhs the same; mod can't be the same as dest
*/
void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t *mod) {
- if (lhs->len == 0 || rhs->neg != 0) {
+ if (lhs->len == 0 || rhs->neg != 0 || (mod->len == 1 && mod->dig[0] == 1)) {
mpz_set_from_int(dest, 0);
return;
}
+ mpz_set_from_int(dest, 1);
+
if (rhs->len == 0) {
- mpz_set_from_int(dest, 1);
return;
}
@@ -1404,8 +1378,6 @@ void mpz_pow3_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs, const mpz_t
mpz_t *n = mpz_clone(rhs);
mpz_t quo; mpz_init_zero(&quo);
- mpz_set_from_int(dest, 1);
-
while (n->len > 0) {
if ((n->dig[0] & 1) != 0) {
mpz_mul_inpl(dest, dest, x);
@@ -1435,6 +1407,7 @@ these functions are unused
*/
mpz_t *mpz_gcd(const mpz_t *z1, const mpz_t *z2) {
if (z1->len == 0) {
+ // TODO: handle case of z2->alloc=0
mpz_t *a = mpz_clone(z2);
a->neg = 0;
return a;
@@ -1559,7 +1532,7 @@ mpz_t *mpz_mod(const mpz_t *lhs, const mpz_t *rhs) {
// must return actual int value if it fits in mp_int_t
mp_int_t mpz_hash(const mpz_t *z) {
- mp_int_t val = 0;
+ mp_uint_t val = 0;
mpz_dig_t *d = z->dig + z->len;
while (d-- > z->dig) {
@@ -1674,16 +1647,12 @@ char *mpz_as_str(const mpz_t *i, unsigned int base) {
}
#endif
-// assumes enough space as calculated by mp_int_format_size
+// assumes enough space in str as calculated by mp_int_format_size
+// base must be between 2 and 32 inclusive
// returns length of string, not including null byte
size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, char base_char, char comma, char *str) {
- if (str == NULL) {
- return 0;
- }
- if (base < 2 || base > 32) {
- str[0] = 0;
- return 0;
- }
+ assert(str != NULL);
+ assert(2 <= base && base <= 32);
size_t ilen = i->len;
diff --git a/py/mpz.h b/py/mpz.h
index e2d0c30aa..3c36cac66 100644
--- a/py/mpz.h
+++ b/py/mpz.h
@@ -55,18 +55,22 @@
#endif
#if MPZ_DIG_SIZE > 16
+#define MPZ_DBL_DIG_SIZE (64)
typedef uint32_t mpz_dig_t;
typedef uint64_t mpz_dbl_dig_t;
typedef int64_t mpz_dbl_dig_signed_t;
#elif MPZ_DIG_SIZE > 8
+#define MPZ_DBL_DIG_SIZE (32)
typedef uint16_t mpz_dig_t;
typedef uint32_t mpz_dbl_dig_t;
typedef int32_t mpz_dbl_dig_signed_t;
#elif MPZ_DIG_SIZE > 4
+#define MPZ_DBL_DIG_SIZE (16)
typedef uint8_t mpz_dig_t;
typedef uint16_t mpz_dbl_dig_t;
typedef int16_t mpz_dbl_dig_signed_t;
#else
+#define MPZ_DBL_DIG_SIZE (8)
typedef uint8_t mpz_dig_t;
typedef uint8_t mpz_dbl_dig_t;
typedef int8_t mpz_dbl_dig_signed_t;
diff --git a/py/nativeglue.c b/py/nativeglue.c
index e63c2fcda..b87da6931 100644
--- a/py/nativeglue.c
+++ b/py/nativeglue.c
@@ -146,8 +146,8 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_obj_new_dict,
mp_obj_dict_store,
#if MICROPY_PY_BUILTINS_SET
- mp_obj_new_set,
mp_obj_set_store,
+ mp_obj_new_set,
#endif
mp_make_function_from_raw_code,
mp_native_call_function_n_kw,
diff --git a/py/nlr.c b/py/nlr.c
new file mode 100644
index 000000000..03d01577e
--- /dev/null
+++ b/py/nlr.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2017 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpstate.h"
+
+#if !MICROPY_NLR_SETJMP
+// When not using setjmp, nlr_push_tail is called from inline asm so needs special care
+#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS
+// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore
+unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
+#else
+// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as used
+__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
+#endif
+#endif
+
+unsigned int nlr_push_tail(nlr_buf_t *nlr) {
+ nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
+ nlr->prev = *top;
+ MP_NLR_SAVE_PYSTACK(nlr);
+ *top = nlr;
+ return 0; // normal return
+}
+
+void nlr_pop(void) {
+ nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
+ *top = (*top)->prev;
+}
diff --git a/py/nlr.h b/py/nlr.h
index 8fa6eb950..90595a12d 100644
--- a/py/nlr.h
+++ b/py/nlr.h
@@ -30,30 +30,34 @@
// exception handling, basically a stack of setjmp/longjmp buffers
#include <limits.h>
-#include <setjmp.h>
#include <assert.h>
#include "py/mpconfig.h"
-typedef struct _nlr_buf_t nlr_buf_t;
-struct _nlr_buf_t {
- // the entries here must all be machine word size
- nlr_buf_t *prev;
- void *ret_val; // always a concrete object (an exception instance)
-#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP
-#define MICROPY_NLR_SETJMP (0)
+// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch
+#if !MICROPY_NLR_SETJMP
+// A lot of nlr-related things need different treatment on Windows
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define MICROPY_NLR_OS_WINDOWS 1
+#else
+#define MICROPY_NLR_OS_WINDOWS 0
+#endif
#if defined(__i386__)
- void *regs[6];
+ #define MICROPY_NLR_X86 (1)
+ #define MICROPY_NLR_NUM_REGS (6)
#elif defined(__x86_64__)
- #if defined(__CYGWIN__)
- void *regs[12];
- #else
- void *regs[8];
- #endif
+ #define MICROPY_NLR_X64 (1)
+ #if MICROPY_NLR_OS_WINDOWS
+ #define MICROPY_NLR_NUM_REGS (10)
+ #else
+ #define MICROPY_NLR_NUM_REGS (8)
+ #endif
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
- void *regs[10];
+ #define MICROPY_NLR_THUMB (1)
+ #define MICROPY_NLR_NUM_REGS (10)
#elif defined(__xtensa__)
- void *regs[10];
+ #define MICROPY_NLR_XTENSA (1)
+ #define MICROPY_NLR_NUM_REGS (10)
#else
#define MICROPY_NLR_SETJMP (1)
//#warning "No native NLR support for this arch, using setjmp implementation"
@@ -61,24 +65,58 @@ struct _nlr_buf_t {
#endif
#if MICROPY_NLR_SETJMP
- jmp_buf jmpbuf;
+#include <setjmp.h>
#endif
+
+typedef struct _nlr_buf_t nlr_buf_t;
+struct _nlr_buf_t {
+ // the entries here must all be machine word size
+ nlr_buf_t *prev;
+ void *ret_val; // always a concrete object (an exception instance)
+
+ #if MICROPY_NLR_SETJMP
+ jmp_buf jmpbuf;
+ #else
+ void *regs[MICROPY_NLR_NUM_REGS];
+ #endif
+
+ #if MICROPY_ENABLE_PYSTACK
+ void *pystack;
+ #endif
};
-#if MICROPY_NLR_SETJMP
-#include "py/mpstate.h"
+// Helper macros to save/restore the pystack state
+#if MICROPY_ENABLE_PYSTACK
+#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur)
+#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack
+#else
+#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf
+#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf
+#endif
+
+// Helper macro to use at the start of a specific nlr_jump implementation
+#define MP_NLR_JUMP_HEAD(val, top) \
+ nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \
+ nlr_buf_t *top = *_top_ptr; \
+ if (top == NULL) { \
+ nlr_jump_fail(val); \
+ } \
+ top->ret_val = val; \
+ MP_NLR_RESTORE_PYSTACK(top); \
+ *_top_ptr = top->prev; \
-NORETURN void nlr_setjmp_jump(void *val);
+#if MICROPY_NLR_SETJMP
// nlr_push() must be defined as a macro, because "The stack context will be
// invalidated if the function which called setjmp() returns."
-#define nlr_push(buf) ((buf)->prev = MP_STATE_THREAD(nlr_top), MP_STATE_THREAD(nlr_top) = (buf), setjmp((buf)->jmpbuf))
-#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; }
-#define nlr_jump(val) nlr_setjmp_jump(val)
+// For this case it is safe to call nlr_push_tail() first.
+#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf))
#else
unsigned int nlr_push(nlr_buf_t *);
+#endif
+
+unsigned int nlr_push_tail(nlr_buf_t *top);
void nlr_pop(void);
NORETURN void nlr_jump(void *val);
-#endif
// This must be implemented by a port. It's called by nlr_jump
// if no nlr buf has been pushed. It must not return, but rather
@@ -107,7 +145,6 @@ NORETURN void nlr_jump_fail(void *val);
/*
#define nlr_push(val) \
printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val)
-#endif
*/
#endif
diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c
index 1fb459440..960dd86f5 100644
--- a/py/nlrsetjmp.c
+++ b/py/nlrsetjmp.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2017 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,17 +24,18 @@
* THE SOFTWARE.
*/
-#include "py/nlr.h"
+#include "py/mpstate.h"
#if MICROPY_NLR_SETJMP
-void nlr_setjmp_jump(void *val) {
+void nlr_jump(void *val) {
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
nlr_buf_t *top = *top_ptr;
if (top == NULL) {
nlr_jump_fail(val);
}
top->ret_val = val;
+ MP_NLR_RESTORE_PYSTACK(top);
*top_ptr = top->prev;
longjmp(top->jmpbuf, 1);
}
diff --git a/py/nlrthumb.c b/py/nlrthumb.c
index 0616e59b0..69d3f868a 100644
--- a/py/nlrthumb.c
+++ b/py/nlrthumb.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013-2016 Damien P. George
+ * Copyright (c) 2013-2017 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +26,7 @@
#include "py/mpstate.h"
-#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#if MICROPY_NLR_THUMB
#undef nlr_push
@@ -82,30 +82,15 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
: "r1", "r2", "r3" // clobbers
);
- return 0; // needed to silence compiler warning
+ #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
+ // Older versions of gcc give an error when naked functions don't return a value
+ // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement
+ return 0;
+ #endif
}
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- nlr->prev = *top;
- *top = nlr;
- return 0; // normal return
-}
-
-void nlr_pop(void) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- *top = (*top)->prev;
-}
-
-NORETURN __attribute__((naked)) void nlr_jump(void *val) {
- nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
- nlr_buf_t *top = *top_ptr;
- if (top == NULL) {
- nlr_jump_fail(val);
- }
-
- top->ret_val = val;
- *top_ptr = top->prev;
+NORETURN void nlr_jump(void *val) {
+ MP_NLR_JUMP_HEAD(val, top)
__asm volatile (
"mov r0, %0 \n" // r0 points to nlr_buf
@@ -142,7 +127,11 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) {
: // clobbered registers
);
+ #if defined(__GNUC__)
+ __builtin_unreachable();
+ #else
for (;;); // needed to silence compiler warning
+ #endif
}
-#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#endif // MICROPY_NLR_THUMB
diff --git a/py/nlrx64.c b/py/nlrx64.c
index 847d10398..a3a1cf341 100644
--- a/py/nlrx64.c
+++ b/py/nlrx64.c
@@ -26,25 +26,19 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__x86_64__)
+#if MICROPY_NLR_X64
#undef nlr_push
// x86-64 callee-save registers are:
// rbx, rbp, rsp, r12, r13, r14, r15
-#if defined(_WIN32) || defined(__CYGWIN__)
-#define NLR_OS_WINDOWS 1
-#else
-#define NLR_OS_WINDOWS 0
-#endif
-
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
unsigned int nlr_push(nlr_buf_t *nlr) {
(void)nlr;
- #if NLR_OS_WINDOWS
+ #if MICROPY_NLR_OS_WINDOWS
__asm volatile (
"movq (%rsp), %rax \n" // load return %rip
@@ -88,31 +82,12 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
return 0; // needed to silence compiler warning
}
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- nlr->prev = *top;
- *top = nlr;
- return 0; // normal return
-}
-
-void nlr_pop(void) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- *top = (*top)->prev;
-}
-
NORETURN void nlr_jump(void *val) {
- nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
- nlr_buf_t *top = *top_ptr;
- if (top == NULL) {
- nlr_jump_fail(val);
- }
-
- top->ret_val = val;
- *top_ptr = top->prev;
+ MP_NLR_JUMP_HEAD(val, top)
__asm volatile (
"movq %0, %%rcx \n" // %rcx points to nlr_buf
- #if NLR_OS_WINDOWS
+ #if MICROPY_NLR_OS_WINDOWS
"movq 88(%%rcx), %%rsi \n" // load saved %rsi
"movq 80(%%rcx), %%rdi \n" // load saved %rdr
#endif
@@ -136,4 +111,4 @@ NORETURN void nlr_jump(void *val) {
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__)
+#endif // MICROPY_NLR_X64
diff --git a/py/nlrx86.c b/py/nlrx86.c
index 094dea3cc..59b97d8ee 100644
--- a/py/nlrx86.c
+++ b/py/nlrx86.c
@@ -26,34 +26,42 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__i386__)
+#if MICROPY_NLR_X86
#undef nlr_push
// For reference, x86 callee save regs are:
// ebx, esi, edi, ebp, esp, eip
-#if defined(_WIN32) || defined(__CYGWIN__)
-#define NLR_OS_WINDOWS 1
+#if MICROPY_NLR_OS_WINDOWS
+unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
#else
-#define NLR_OS_WINDOWS 0
+__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
#endif
-#if NLR_OS_WINDOWS
-unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8
+// Since gcc 8.0 the naked attribute is supported
+#define USE_NAKED (1)
+#define UNDO_PRELUDE (0)
+#elif defined(__ZEPHYR__) || defined(__ANDROID__)
+// Zephyr and Android use a different calling convention by default
+#define USE_NAKED (0)
+#define UNDO_PRELUDE (0)
#else
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
+#define USE_NAKED (0)
+#define UNDO_PRELUDE (1)
#endif
+#if USE_NAKED
+__attribute__((naked))
+#endif
unsigned int nlr_push(nlr_buf_t *nlr) {
+ #if !USE_NAKED
(void)nlr;
+ #endif
__asm volatile (
- // Check for Zephyr, which uses a different calling convention
- // by default.
- // TODE: Better support for various x86 calling conventions
- // (unfortunately, __attribute__((naked)) is not supported on x86).
- #if !(defined(__ZEPHYR__) || defined(__ANDROID__))
+ #if UNDO_PRELUDE
"pop %ebp \n" // undo function's prelude
#endif
"mov 4(%esp), %edx \n" // load nlr_buf
@@ -67,30 +75,13 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
"jmp nlr_push_tail \n" // do the rest in C
);
+ #if !USE_NAKED
return 0; // needed to silence compiler warning
-}
-
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- nlr->prev = *top;
- *top = nlr;
- return 0; // normal return
-}
-
-void nlr_pop(void) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- *top = (*top)->prev;
+ #endif
}
NORETURN void nlr_jump(void *val) {
- nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
- nlr_buf_t *top = *top_ptr;
- if (top == NULL) {
- nlr_jump_fail(val);
- }
-
- top->ret_val = val;
- *top_ptr = top->prev;
+ MP_NLR_JUMP_HEAD(val, top)
__asm volatile (
"mov %0, %%edx \n" // %edx points to nlr_buf
@@ -112,4 +103,4 @@ NORETURN void nlr_jump(void *val) {
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__i386__)
+#endif // MICROPY_NLR_X86
diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c
index 4520e7e7a..cd3dee364 100644
--- a/py/nlrxtensa.c
+++ b/py/nlrxtensa.c
@@ -26,7 +26,7 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__xtensa__)
+#if MICROPY_NLR_XTENSA
#undef nlr_push
@@ -55,27 +55,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
return 0; // needed to silence compiler warning
}
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- nlr->prev = *top;
- *top = nlr;
- return 0; // normal return
-}
-
-void nlr_pop(void) {
- nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
- *top = (*top)->prev;
-}
-
NORETURN void nlr_jump(void *val) {
- nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
- nlr_buf_t *top = *top_ptr;
- if (top == NULL) {
- nlr_jump_fail(val);
- }
-
- top->ret_val = val;
- *top_ptr = top->prev;
+ MP_NLR_JUMP_HEAD(val, top)
__asm volatile (
"mov.n a2, %0 \n" // a2 points to nlr_buf
@@ -99,4 +80,4 @@ NORETURN void nlr_jump(void *val) {
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__)
+#endif // MICROPY_NLR_XTENSA
diff --git a/py/obj.h b/py/obj.h
index d086d3c14..42c88ef67 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -172,8 +172,8 @@ static inline bool MP_OBJ_IS_OBJ(mp_const_obj_t o)
static inline bool MP_OBJ_IS_SMALL_INT(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0001000000000000); }
-#define MP_OBJ_SMALL_INT_VALUE(o) (((intptr_t)(o)) >> 1)
-#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)(((uintptr_t)(small_int)) << 1) | 0x0001000000000001)
+#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17)
+#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001)
static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
{ return ((((mp_int_t)(o)) & 0xffff000000000000) == 0x0002000000000000); }
@@ -181,7 +181,7 @@ static inline bool MP_OBJ_IS_QSTR(mp_const_obj_t o)
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 1) | 0x0002000000000001))
#if MICROPY_PY_BUILTINS_FLOAT
-#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b125769 + 0x8004000000000000))}
+#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}
#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}
static inline bool mp_obj_is_float(mp_const_obj_t o) {
@@ -252,6 +252,8 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
// The macros below are derived from the ones above and are used to
// check for more specific object types.
+// Note: these are kept as macros because inline functions sometimes use much
+// more code space than the equivalent macros, depending on the compiler.
#define MP_OBJ_IS_TYPE(o, t) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type == (t))) // this does not work for checking int, str or fun; use below macros for that
#define MP_OBJ_IS_INT(o) (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int))
@@ -259,17 +261,6 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
#define MP_OBJ_IS_STR_OR_BYTES(o) (MP_OBJ_IS_QSTR(o) || (MP_OBJ_IS_OBJ(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->binary_op == mp_obj_str_binary_op))
#define MP_OBJ_IS_FUN(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_function))
-// Note: inline functions sometimes use much more code space than the
-// equivalent macros, depending on the compiler.
-//static inline bool MP_OBJ_IS_TYPE(mp_const_obj_t o, const mp_obj_type_t *t) { return (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)(o))->type == (t))); } // this does not work for checking a string, use below macro for that
-//static inline bool MP_OBJ_IS_INT(mp_const_obj_t o) { return (MP_OBJ_IS_SMALL_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_int)); } // returns true if o is a small int or long int
-// Need to forward declare these for the inline function to compile.
-extern const mp_obj_type_t mp_type_int;
-extern const mp_obj_type_t mp_type_bool;
-static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
-//static inline bool MP_OBJ_IS_STR(mp_const_obj_t o) { return (MP_OBJ_IS_QSTR(o) || MP_OBJ_IS_TYPE(o, &mp_type_str)); }
-
-
// These macros are used to declare and define constant function objects
// You can put "static" in front of the definitions to make them local
@@ -462,22 +453,15 @@ typedef struct _mp_buffer_p_t {
bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
-// Stream protocol
-typedef struct _mp_stream_p_t {
- // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
- // are implementation-dependent, but will be exposed to user, e.g. via exception).
- mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
- mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
- mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
- mp_uint_t is_text : 1; // default is bytes, set this for text stream
-} mp_stream_p_t;
-
struct _mp_obj_type_t {
// A type is an object so must start with this entry, which points to mp_type_type.
mp_obj_base_t base;
- // The name of this type.
- qstr name;
+ // Flags associated with this type.
+ uint16_t flags;
+
+ // The name of this type, a qstr.
+ uint16_t name;
// Corresponds to __repr__ and __str__ special methods.
mp_print_fun_t print;
@@ -553,6 +537,7 @@ extern const mp_obj_type_t mp_type_list;
extern const mp_obj_type_t mp_type_map; // map (the python builtin, not the dict implementation detail)
extern const mp_obj_type_t mp_type_enumerate;
extern const mp_obj_type_t mp_type_filter;
+extern const mp_obj_type_t mp_type_deque;
extern const mp_obj_type_t mp_type_dict;
extern const mp_obj_type_t mp_type_ordereddict;
extern const mp_obj_type_t mp_type_range;
@@ -625,7 +610,6 @@ extern const struct _mp_obj_str_t mp_const_empty_bytes_obj;
extern const struct _mp_obj_tuple_t mp_const_empty_tuple_obj;
extern const struct _mp_obj_singleton_t mp_const_ellipsis_obj;
extern const struct _mp_obj_singleton_t mp_const_notimplemented_obj;
-extern const struct _mp_obj_exception_t mp_const_MemoryError_obj;
extern const struct _mp_obj_exception_t mp_const_GeneratorExit_obj;
// General API for objects
@@ -638,7 +622,8 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base);
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception)
-mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already);
+mp_obj_t mp_obj_new_str(const char* data, size_t len);
+mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len);
mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr);
mp_obj_t mp_obj_new_bytes(const byte* data, size_t len);
mp_obj_t mp_obj_new_bytearray(size_t n, void *items);
@@ -682,6 +667,7 @@ bool mp_obj_is_true(mp_obj_t arg);
bool mp_obj_is_callable(mp_obj_t o_in);
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
+static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) || MP_OBJ_IS_TYPE(o, &mp_type_bool); } // returns true if o is bool, small int or long int
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
@@ -729,6 +715,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len);
mp_obj_t mp_obj_str_intern(mp_obj_t str);
+mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj);
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes);
#if MICROPY_PY_BUILTINS_FLOAT
@@ -753,8 +740,6 @@ void mp_obj_tuple_del(mp_obj_t self_in);
mp_int_t mp_obj_tuple_hash(mp_obj_t self_in);
// list
-struct _mp_obj_list_t;
-void mp_obj_list_init(struct _mp_obj_list_t *o, size_t n);
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value);
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);
diff --git a/py/objarray.c b/py/objarray.c
index c4c547e19..94f887857 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -222,7 +222,7 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args,
// test if the object can be written to
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
- self->typecode |= 0x80; // used to indicate writable buffer
+ self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
}
return MP_OBJ_FROM_PTR(self);
@@ -302,8 +302,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
return lhs_in;
}
- case MP_BINARY_OP_IN: {
- /* NOTE `a in b` is `b.__contains__(a)` */
+ case MP_BINARY_OP_CONTAINS: {
mp_buffer_info_t lhs_bufinfo;
mp_buffer_info_t rhs_bufinfo;
@@ -448,7 +447,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
uint8_t* dest_items = o->items;
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (o->base.type == &mp_type_memoryview) {
- if ((o->typecode & 0x80) == 0) {
+ if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
// store to read-only memoryview not allowed
return MP_OBJ_NULL;
}
@@ -507,7 +506,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (o->base.type == &mp_type_memoryview) {
index += o->free;
- if (value != MP_OBJ_SENTINEL && (o->typecode & 0x80) == 0) {
+ if (value != MP_OBJ_SENTINEL && !(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
// store to read-only memoryview
return MP_OBJ_NULL;
}
@@ -533,7 +532,7 @@ STATIC mp_int_t array_get_buffer(mp_obj_t o_in, mp_buffer_info_t *bufinfo, mp_ui
bufinfo->typecode = o->typecode & TYPECODE_MASK;
#if MICROPY_PY_BUILTINS_MEMORYVIEW
if (o->base.type == &mp_type_memoryview) {
- if ((o->typecode & 0x80) == 0 && (flags & MP_BUFFER_WRITE)) {
+ if (!(o->typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW) && (flags & MP_BUFFER_WRITE)) {
// read-only memoryview
return 1;
}
diff --git a/py/objarray.h b/py/objarray.h
index 038966845..0dad70571 100644
--- a/py/objarray.h
+++ b/py/objarray.h
@@ -29,6 +29,9 @@
#include "py/obj.h"
+// Used only for memoryview types, set in "typecode" to indicate a writable memoryview
+#define MP_OBJ_ARRAY_TYPECODE_FLAG_RW (0x80)
+
typedef struct _mp_obj_array_t {
mp_obj_base_t base;
size_t typecode : 8;
diff --git a/py/objboundmeth.c b/py/objboundmeth.c
index 890f8b15b..b0df6a68a 100644
--- a/py/objboundmeth.c
+++ b/py/objboundmeth.c
@@ -51,6 +51,9 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s
// need to insert self before all other args and then call meth
size_t n_total = n_args + 2 * n_kw;
mp_obj_t *args2 = NULL;
+ #if MICROPY_ENABLE_PYSTACK
+ args2 = mp_pystack_alloc(sizeof(mp_obj_t) * (1 + n_total));
+ #else
mp_obj_t *free_args2 = NULL;
if (n_total > 4) {
// try to use heap to allocate temporary args array
@@ -61,12 +64,17 @@ mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, s
// (fallback to) use stack to allocate temporary args array
args2 = alloca(sizeof(mp_obj_t) * (1 + n_total));
}
+ #endif
args2[0] = self;
memcpy(args2 + 1, args, n_total * sizeof(mp_obj_t));
mp_obj_t res = mp_call_function_n_kw(meth, n_args + 1, n_kw, args2);
+ #if MICROPY_ENABLE_PYSTACK
+ mp_pystack_free(args2);
+ #else
if (free_args2 != NULL) {
m_del(mp_obj_t, free_args2, 1 + n_total);
}
+ #endif
return res;
}
diff --git a/py/objdeque.c b/py/objdeque.c
new file mode 100644
index 000000000..1cff1f8d3
--- /dev/null
+++ b/py/objdeque.c
@@ -0,0 +1,167 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <unistd.h> // for ssize_t
+#include <string.h>
+
+#include "py/mpconfig.h"
+#if MICROPY_PY_COLLECTIONS_DEQUE
+
+#include "py/runtime.h"
+
+typedef struct _mp_obj_deque_t {
+ mp_obj_base_t base;
+ size_t alloc;
+ size_t i_get;
+ size_t i_put;
+ mp_obj_t *items;
+ uint32_t flags;
+ #define FLAG_CHECK_OVERFLOW 1
+} mp_obj_deque_t;
+
+STATIC mp_obj_t deque_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 2, 3, false);
+
+ /* Initialization from existing sequence is not supported, so an empty
+ tuple must be passed as such. */
+ if (args[0] != mp_const_empty_tuple) {
+ mp_raise_ValueError(NULL);
+ }
+
+ // Protect against -1 leading to zero-length allocation and bad array access
+ mp_int_t maxlen = mp_obj_get_int(args[1]);
+ if (maxlen < 0) {
+ mp_raise_ValueError(NULL);
+ }
+
+ mp_obj_deque_t *o = m_new_obj(mp_obj_deque_t);
+ o->base.type = type;
+ o->alloc = maxlen + 1;
+ o->i_get = o->i_put = 0;
+ o->items = m_new0(mp_obj_t, o->alloc);
+
+ if (n_args > 2) {
+ o->flags = mp_obj_get_int(args[2]);
+ }
+
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(self->i_get != self->i_put);
+ case MP_UNARY_OP_LEN: {
+ ssize_t len = self->i_put - self->i_get;
+ if (len < 0) {
+ len += self->alloc;
+ }
+ return MP_OBJ_NEW_SMALL_INT(len);
+ }
+ #if MICROPY_PY_SYS_GETSIZEOF
+ case MP_UNARY_OP_SIZEOF: {
+ size_t sz = sizeof(*self) + sizeof(mp_obj_t) * self->alloc;
+ return MP_OBJ_NEW_SMALL_INT(sz);
+ }
+ #endif
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
+
+ size_t new_i_put = self->i_put + 1;
+ if (new_i_put == self->alloc) {
+ new_i_put = 0;
+ }
+
+ if (self->flags & FLAG_CHECK_OVERFLOW && new_i_put == self->i_get) {
+ mp_raise_msg(&mp_type_IndexError, "full");
+ }
+
+ self->items[self->i_put] = arg;
+ self->i_put = new_i_put;
+
+ if (self->i_get == new_i_put) {
+ if (++self->i_get == self->alloc) {
+ self->i_get = 0;
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append);
+
+STATIC mp_obj_t deque_popleft(mp_obj_t self_in) {
+ mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->i_get == self->i_put) {
+ mp_raise_msg(&mp_type_IndexError, "empty");
+ }
+
+ mp_obj_t ret = self->items[self->i_get];
+ self->items[self->i_get] = MP_OBJ_NULL;
+
+ if (++self->i_get == self->alloc) {
+ self->i_get = 0;
+ }
+
+ return ret;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft);
+
+#if 0
+STATIC mp_obj_t deque_clear(mp_obj_t self_in) {
+ mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in);
+ self->i_get = self->i_put = 0;
+ mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(deque_clear_obj, deque_clear);
+#endif
+
+STATIC const mp_rom_map_elem_t deque_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&deque_append_obj) },
+ #if 0
+ { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&deque_clear_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&deque_popleft_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table);
+
+const mp_obj_type_t mp_type_deque = {
+ { &mp_type_type },
+ .name = MP_QSTR_deque,
+ .make_new = deque_make_new,
+ .unary_op = deque_unary_op,
+ .locals_dict = (mp_obj_dict_t*)&deque_locals_dict,
+};
+
+#endif // MICROPY_PY_COLLECTIONS_DEQUE
diff --git a/py/objdict.c b/py/objdict.c
index 1553a83b4..c0647067a 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -115,7 +115,7 @@ STATIC mp_obj_t dict_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
STATIC mp_obj_t dict_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_dict_t *o = MP_OBJ_TO_PTR(lhs_in);
switch (op) {
- case MP_BINARY_OP_IN: {
+ case MP_BINARY_OP_CONTAINS: {
mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP);
return mp_obj_new_bool(elem != NULL);
}
@@ -193,42 +193,18 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
}
/******************************************************************************/
-/* dict iterator */
-
-typedef struct _mp_obj_dict_it_t {
- mp_obj_base_t base;
- mp_fun_1_t iternext;
- mp_obj_t dict;
- size_t cur;
-} mp_obj_dict_it_t;
-
-STATIC mp_obj_t dict_it_iternext(mp_obj_t self_in) {
- mp_obj_dict_it_t *self = MP_OBJ_TO_PTR(self_in);
- mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur);
+/* dict methods */
- if (next == NULL) {
- return MP_OBJ_STOP_ITERATION;
- } else {
- return next->key;
+STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
+ if (dict->map.is_fixed) {
+ mp_raise_TypeError(NULL);
}
}
-STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
- assert(sizeof(mp_obj_dict_it_t) <= sizeof(mp_obj_iter_buf_t));
- mp_obj_dict_it_t *o = (mp_obj_dict_it_t*)iter_buf;
- o->base.type = &mp_type_polymorph_iter;
- o->iternext = dict_it_iternext;
- o->dict = self_in;
- o->cur = 0;
- return MP_OBJ_FROM_PTR(o);
-}
-
-/******************************************************************************/
-/* dict methods */
-
STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_ensure_not_fixed(self);
mp_map_clear(&self->map);
@@ -284,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk
STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (lookup_kind != MP_MAP_LOOKUP) {
+ mp_ensure_not_fixed(self);
+ }
mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind);
mp_obj_t value;
if (elem == NULL || elem->value == MP_OBJ_NULL) {
@@ -326,6 +305,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde
STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_ensure_not_fixed(self);
size_t cur = 0;
mp_map_elem_t *next = dict_iter_next(self, &cur);
if (next == NULL) {
@@ -344,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_ensure_not_fixed(self);
mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
@@ -485,7 +466,7 @@ STATIC mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t
if (o->kind != MP_DICT_VIEW_KEYS) {
return MP_OBJ_NULL; // op not supported
}
- if (op != MP_BINARY_OP_IN) {
+ if (op != MP_BINARY_OP_CONTAINS) {
return MP_OBJ_NULL; // op not supported
}
return dict_binary_op(op, o->dict, rhs_in);
@@ -528,6 +509,20 @@ STATIC mp_obj_t dict_values(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
/******************************************************************************/
+/* dict iterator */
+
+STATIC mp_obj_t dict_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
+ assert(sizeof(mp_obj_dict_view_it_t) <= sizeof(mp_obj_iter_buf_t));
+ mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
+ mp_obj_dict_view_it_t *o = (mp_obj_dict_view_it_t*)iter_buf;
+ o->base.type = &dict_view_it_type;
+ o->kind = MP_DICT_VIEW_KEYS;
+ o->dict = self_in;
+ o->cur = 0;
+ return MP_OBJ_FROM_PTR(o);
+}
+
+/******************************************************************************/
/* dict constructors & public C API */
STATIC const mp_rom_map_elem_t dict_locals_dict_table[] = {
@@ -595,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_ensure_not_fixed(self);
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
return self_in;
}
diff --git a/py/objexcept.c b/py/objexcept.c
index f0874df77..5b5650c5f 100644
--- a/py/objexcept.c
+++ b/py/objexcept.c
@@ -43,9 +43,6 @@
// Number of traceback entries to reserve in the emergency exception buffer
#define EMG_TRACEBACK_ALLOC (2 * TRACEBACK_ENTRY_LEN)
-// Instance of MemoryError exception - needed by mp_malloc_fail
-const mp_obj_exception_t mp_const_MemoryError_obj = {{&mp_type_MemoryError}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj};
-
// Optionally allocated buffer for storing the first argument of an exception
// allocated when the heap is locked.
#if MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
@@ -96,7 +93,7 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
// definition module-private so far, have it here.
const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, 0, 0, NULL, (mp_obj_tuple_t*)&mp_const_empty_tuple_obj};
-STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_exception_t *o = MP_OBJ_TO_PTR(o_in);
mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
bool is_subclass = kind & PRINT_EXC_SUBCLASS;
@@ -117,7 +114,7 @@ STATIC void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr
if (o->base.type == &mp_type_OSError && MP_OBJ_IS_SMALL_INT(o->args->items[0])) {
qstr qst = mp_errno_to_str(o->args->items[0]);
if (qst != MP_QSTR_NULL) {
- mp_printf(print, "[Errno %d] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst);
+ mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst);
return;
}
}
@@ -187,7 +184,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) {
}
}
-STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_exception_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] != MP_OBJ_NULL) {
// store/delete attribute
@@ -210,37 +207,12 @@ STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
}
}
-STATIC mp_obj_t exc___init__(size_t n_args, const mp_obj_t *args) {
- mp_obj_exception_t *self = MP_OBJ_TO_PTR(args[0]);
- mp_obj_t argst = mp_obj_new_tuple(n_args - 1, args + 1);
- self->args = MP_OBJ_TO_PTR(argst);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(exc___init___obj, 1, MP_OBJ_FUN_ARGS_MAX, exc___init__);
-
-STATIC const mp_rom_map_elem_t exc_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&exc___init___obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(exc_locals_dict, exc_locals_dict_table);
-
const mp_obj_type_t mp_type_BaseException = {
{ &mp_type_type },
.name = MP_QSTR_BaseException,
.print = mp_obj_exception_print,
.make_new = mp_obj_exception_make_new,
- .attr = exception_attr,
- .locals_dict = (mp_obj_dict_t*)&exc_locals_dict,
-};
-
-#define MP_DEFINE_EXCEPTION(exc_name, base_name) \
-const mp_obj_type_t mp_type_ ## exc_name = { \
- { &mp_type_type }, \
- .name = MP_QSTR_ ## exc_name, \
- .print = mp_obj_exception_print, \
- .make_new = mp_obj_exception_make_new, \
- .attr = exception_attr, \
- .parent = &mp_type_ ## base_name, \
+ .attr = mp_obj_exception_attr,
};
// List of all exceptions, arranged as in the table at:
diff --git a/py/objexcept.h b/py/objexcept.h
index f67651a7e..7c3076224 100644
--- a/py/objexcept.h
+++ b/py/objexcept.h
@@ -37,4 +37,17 @@ typedef struct _mp_obj_exception_t {
mp_obj_tuple_t *args;
} mp_obj_exception_t;
+void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
+void mp_obj_exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
+
+#define MP_DEFINE_EXCEPTION(exc_name, base_name) \
+const mp_obj_type_t mp_type_ ## exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_ ## exc_name, \
+ .print = mp_obj_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .attr = mp_obj_exception_attr, \
+ .parent = &mp_type_ ## base_name, \
+};
+
#endif // MICROPY_INCLUDED_PY_OBJEXCEPT_H
diff --git a/py/objfloat.c b/py/objfloat.c
index fde2224ad..16aa9bc20 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -91,7 +91,7 @@ typedef uint32_t mp_float_uint_t;
if (adj_exp <= MP_FLOAT_FRAC_BITS) {
// number may have a fraction; xor the integer part with the fractional part
val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp))
- ^ (frc & ((1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));
+ ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));
} else if ((unsigned int)adj_exp < BITS_PER_BYTE * sizeof(mp_int_t) - 1) {
// the number is a (big) whole integer and will fit in val's signed-width
val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS);
@@ -102,7 +102,7 @@ typedef uint32_t mp_float_uint_t;
}
if (u.p.sgn) {
- val = -val;
+ val = -(mp_uint_t)val;
}
return val;
@@ -140,12 +140,11 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size
return mp_obj_new_float(0);
case 1:
- default:
- if (MP_OBJ_IS_STR(args[0])) {
- // a string, parse it
- size_t l;
- const char *s = mp_obj_str_get_data(args[0], &l);
- return mp_parse_num_decimal(s, l, false, false, NULL);
+ default: {
+ mp_buffer_info_t bufinfo;
+ if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
+ // a textual representation, parse it
+ return mp_parse_num_decimal(bufinfo.buf, bufinfo.len, false, false, NULL);
} else if (mp_obj_is_float(args[0])) {
// a float, just return it
return args[0];
@@ -153,6 +152,7 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size
// something else, try to cast it to a float
return mp_obj_new_float(mp_obj_get_float(args[0]));
}
+ }
}
}
@@ -296,7 +296,7 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
break;
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER:
- if (lhs_val == 0 && rhs_val < 0) {
+ if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {
goto zero_division_error;
}
if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val)) {
diff --git a/py/objfun.c b/py/objfun.c
index 030b3f7cb..8c51d92e0 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -195,32 +195,54 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
// than this will try to use the heap, with fallback to stack allocation.
#define VM_MAX_STATE_ON_STACK (11 * sizeof(mp_uint_t))
-// Set this to enable a simple stack overflow check.
+// Set this to 1 to enable a simple stack overflow check.
#define VM_DETECT_STACK_OVERFLOW (0)
+#define DECODE_CODESTATE_SIZE(bytecode, n_state_out_var, state_size_out_var) \
+ { \
+ /* bytecode prelude: state size and exception stack size */ \
+ n_state_out_var = mp_decode_uint_value(bytecode); \
+ size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(bytecode)); \
+ \
+ n_state_out_var += VM_DETECT_STACK_OVERFLOW; \
+ \
+ /* state size in bytes */ \
+ state_size_out_var = n_state_out_var * sizeof(mp_obj_t) \
+ + n_exc_stack * sizeof(mp_exc_stack_t); \
+ }
+
+#define INIT_CODESTATE(code_state, _fun_bc, n_args, n_kw, args) \
+ code_state->fun_bc = _fun_bc; \
+ code_state->ip = 0; \
+ mp_setup_code_state(code_state, n_args, n_kw, args); \
+ code_state->old_globals = mp_globals_get();
+
#if MICROPY_STACKLESS
mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
MP_STACK_CHECK();
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
- // bytecode prelude: state size and exception stack size
- size_t n_state = mp_decode_uint_value(self->bytecode);
- size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode));
+ size_t n_state, state_size;
+ DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size);
- // allocate state for locals and stack
- size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
mp_code_state_t *code_state;
+ #if MICROPY_ENABLE_PYSTACK
+ code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size);
+ #else
+ // If we use m_new_obj_var(), then on no memory, MemoryError will be
+ // raised. But this is not correct exception for a function call,
+ // RuntimeError should be raised instead. So, we use m_new_obj_var_maybe(),
+ // return NULL, then vm.c takes the needed action (either raise
+ // RuntimeError or fallback to stack allocation).
code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size);
if (!code_state) {
return NULL;
}
+ #endif
- code_state->fun_bc = self;
- code_state->ip = 0;
- mp_setup_code_state(code_state, n_args, n_kw, args);
+ INIT_CODESTATE(code_state, self, n_args, n_kw, args);
// execute the byte code with the correct globals context
- code_state->old_globals = mp_globals_get();
mp_globals_set(self->globals);
return code_state;
@@ -238,17 +260,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in);
DEBUG_printf("Func n_def_args: %d\n", self->n_def_args);
- // bytecode prelude: state size and exception stack size
- size_t n_state = mp_decode_uint_value(self->bytecode);
- size_t n_exc_stack = mp_decode_uint_value(mp_decode_uint_skip(self->bytecode));
-
-#if VM_DETECT_STACK_OVERFLOW
- n_state += 1;
-#endif
+ size_t n_state, state_size;
+ DECODE_CODESTATE_SIZE(self->bytecode, n_state, state_size);
// allocate state for locals and stack
- size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t);
mp_code_state_t *code_state = NULL;
+ #if MICROPY_ENABLE_PYSTACK
+ code_state = mp_pystack_alloc(sizeof(mp_code_state_t) + state_size);
+ #else
if (state_size > VM_MAX_STATE_ON_STACK) {
code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size);
}
@@ -256,13 +275,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
code_state = alloca(sizeof(mp_code_state_t) + state_size);
state_size = 0; // indicate that we allocated using alloca
}
+ #endif
- code_state->fun_bc = self;
- code_state->ip = 0;
- mp_setup_code_state(code_state, n_args, n_kw, args);
+ INIT_CODESTATE(code_state, self, n_args, n_kw, args);
// execute the byte code with the correct globals context
- code_state->old_globals = mp_globals_get();
mp_globals_set(self->globals);
mp_vm_return_kind_t vm_return_kind = mp_execute_bytecode(code_state, MP_OBJ_NULL);
mp_globals_set(code_state->old_globals);
@@ -304,10 +321,14 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
result = code_state->state[n_state - 1];
}
+ #if MICROPY_ENABLE_PYSTACK
+ mp_pystack_free(code_state);
+ #else
// free the state if it was allocated on the heap
if (state_size != 0) {
m_del_var(mp_code_state_t, byte, state_size, code_state);
}
+ #endif
if (vm_return_kind == MP_VM_RETURN_NORMAL) {
return result;
diff --git a/py/objgenerator.c b/py/objgenerator.c
index ff566c076..5664052f5 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -4,7 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2014-2017 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -106,12 +106,31 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
mp_raise_TypeError("can't send non-None value to a just-started generator");
}
} else {
- *self->code_state.sp = send_value;
+ #if MICROPY_PY_GENERATOR_PEND_THROW
+ // If exception is pending (set using .pend_throw()), process it now.
+ if (*self->code_state.sp != mp_const_none) {
+ throw_value = *self->code_state.sp;
+ *self->code_state.sp = MP_OBJ_NULL;
+ } else
+ #endif
+ {
+ *self->code_state.sp = send_value;
+ }
+ }
+
+ // We set self->globals=NULL while executing, for a sentinel to ensure the generator
+ // cannot be reentered during execution
+ if (self->globals == NULL) {
+ mp_raise_ValueError("generator already executing");
}
- mp_obj_dict_t *old_globals = mp_globals_get();
+
+ // Set up the correct globals context for the generator and execute it
+ self->code_state.old_globals = mp_globals_get();
mp_globals_set(self->globals);
+ self->globals = NULL;
mp_vm_return_kind_t ret_kind = mp_execute_bytecode(&self->code_state, throw_value);
- mp_globals_set(old_globals);
+ self->globals = mp_globals_get();
+ mp_globals_set(self->code_state.old_globals);
switch (ret_kind) {
case MP_VM_RETURN_NORMAL:
@@ -127,9 +146,9 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
case MP_VM_RETURN_YIELD:
*ret_val = *self->code_state.sp;
- if (*ret_val == MP_OBJ_STOP_ITERATION) {
- self->code_state.ip = 0;
- }
+ #if MICROPY_PY_GENERATOR_PEND_THROW
+ *self->code_state.sp = mp_const_none;
+ #endif
break;
case MP_VM_RETURN_EXCEPTION: {
@@ -224,10 +243,24 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_close_obj, gen_instance_close);
+STATIC mp_obj_t gen_instance_pend_throw(mp_obj_t self_in, mp_obj_t exc_in) {
+ mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->code_state.sp == self->code_state.state - 1) {
+ mp_raise_TypeError("can't pend throw to just-started generator");
+ }
+ mp_obj_t prev = *self->code_state.sp;
+ *self->code_state.sp = exc_in;
+ return prev;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_pend_throw_obj, gen_instance_pend_throw);
+
STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) },
{ MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) },
+ #if MICROPY_PY_GENERATOR_PEND_THROW
+ { MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) },
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table);
diff --git a/py/objint.c b/py/objint.c
index 4f2e610a5..270e16969 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -222,27 +222,26 @@ size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char co
char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
fmt_int_t num;
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+ // Only have small ints; get the integer value to format.
+ num = MP_OBJ_SMALL_INT_VALUE(self_in);
+ #else
if (MP_OBJ_IS_SMALL_INT(self_in)) {
// A small int; get the integer value to format.
num = MP_OBJ_SMALL_INT_VALUE(self_in);
-#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
- } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
+ } else {
+ assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
// Not a small int.
-#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
const mp_obj_int_t *self = self_in;
// Get the value to format; mp_obj_get_int truncates to mp_int_t.
num = self->val;
-#else
+ #else
// Delegate to the implementation for the long int.
return mp_obj_int_formatted_impl(buf, buf_size, fmt_size, self_in, base, prefix, base_char, comma);
-#endif
-#endif
- } else {
- // Not an int.
- **buf = '\0';
- *fmt_size = 0;
- return *buf;
+ #endif
}
+ #endif
char sign = '\0';
if (num < 0) {
@@ -378,7 +377,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp
// true acts as 0
return mp_binary_op(op, lhs_in, MP_OBJ_NEW_SMALL_INT(1));
} else if (op == MP_BINARY_OP_MULTIPLY) {
- if (MP_OBJ_IS_STR(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_bytes) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
+ if (MP_OBJ_IS_STR_OR_BYTES(rhs_in) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(rhs_in, &mp_type_list)) {
// multiply is commutative for these types, so delegate to them
return mp_binary_op(op, rhs_in, lhs_in);
}
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index 2e567c572..cb8d1672d 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -124,10 +124,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
if (MP_OBJ_IS_SMALL_INT(lhs_in)) {
lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in);
- } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
- lhs_val = ((mp_obj_int_t*)lhs_in)->val;
} else {
- return MP_OBJ_NULL; // op not supported
+ assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int));
+ lhs_val = ((mp_obj_int_t*)lhs_in)->val;
}
if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
@@ -151,9 +150,15 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
return mp_obj_new_int_from_ll(lhs_val * rhs_val);
case MP_BINARY_OP_FLOOR_DIVIDE:
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
+ if (rhs_val == 0) {
+ goto zero_division;
+ }
return mp_obj_new_int_from_ll(lhs_val / rhs_val);
case MP_BINARY_OP_MODULO:
case MP_BINARY_OP_INPLACE_MODULO:
+ if (rhs_val == 0) {
+ goto zero_division;
+ }
return mp_obj_new_int_from_ll(lhs_val % rhs_val);
case MP_BINARY_OP_AND:
@@ -210,6 +215,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
default:
return MP_OBJ_NULL; // op not supported
}
+
+zero_division:
+ mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero");
}
mp_obj_t mp_obj_new_int(mp_int_t value) {
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 808fae6e4..6ee128640 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -170,11 +170,9 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
if (MP_OBJ_IS_SMALL_INT(lhs_in)) {
mpz_init_fixed_from_int(&z_int, z_int_dig, MPZ_NUM_DIG_FOR_INT, MP_OBJ_SMALL_INT_VALUE(lhs_in));
zlhs = &z_int;
- } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
- zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz;
} else {
- // unsupported type
- return MP_OBJ_NULL;
+ assert(MP_OBJ_IS_TYPE(lhs_in, &mp_type_int));
+ zlhs = &((mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in))->mpz;
}
// if rhs is small int, then lhs was not (otherwise mp_binary_op handles it)
@@ -207,7 +205,7 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
return mp_obj_new_float(flhs / frhs);
#endif
- } else if (op >= MP_BINARY_OP_INPLACE_OR) {
+ } else if (op >= MP_BINARY_OP_INPLACE_OR && op < MP_BINARY_OP_CONTAINS) {
mp_obj_int_t *res = mp_obj_int_new_mpz();
switch (op) {
diff --git a/py/objlist.h b/py/objlist.h
index 28b5495a9..a43663db7 100644
--- a/py/objlist.h
+++ b/py/objlist.h
@@ -35,4 +35,6 @@ typedef struct _mp_obj_list_t {
mp_obj_t *items;
} mp_obj_list_t;
+void mp_obj_list_init(mp_obj_list_t *o, size_t n);
+
#endif // MICROPY_INCLUDED_PY_OBJLIST_H
diff --git a/py/objmodule.c b/py/objmodule.c
index e3464ecfa..b28fb2416 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -259,17 +259,7 @@ mp_obj_t mp_module_get(qstr module_name) {
if (el == NULL) {
return MP_OBJ_NULL;
}
-
- if (MICROPY_MODULE_BUILTIN_INIT) {
- // look for __init__ and call it if it exists
- mp_obj_t dest[2];
- mp_load_method_maybe(el->value, MP_QSTR___init__, dest);
- if (dest[0] != MP_OBJ_NULL) {
- mp_call_method_n_kw(0, 0, dest);
- // register module so __init__ is not called again
- mp_module_register(module_name, el->value);
- }
- }
+ mp_module_call_init(module_name, el->value);
}
// module found, return it
@@ -280,3 +270,19 @@ void mp_module_register(qstr qst, mp_obj_t module) {
mp_map_t *mp_loaded_modules_map = &MP_STATE_VM(mp_loaded_modules_dict).map;
mp_map_lookup(mp_loaded_modules_map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = module;
}
+
+#if MICROPY_MODULE_BUILTIN_INIT
+void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
+ // Look for __init__ and call it if it exists
+ mp_obj_t dest[2];
+ mp_load_method_maybe(module_obj, MP_QSTR___init__, dest);
+ if (dest[0] != MP_OBJ_NULL) {
+ mp_call_method_n_kw(0, 0, dest);
+ // Register module so __init__ is not called again.
+ // If a module can be referenced by more than one name (eg due to weak links)
+ // then __init__ will still be called for each distinct import, and it's then
+ // up to the particular module to make sure it's __init__ code only runs once.
+ mp_module_register(module_name, module_obj);
+ }
+}
+#endif
diff --git a/py/objmodule.h b/py/objmodule.h
index b5c07dc33..b7702ec50 100644
--- a/py/objmodule.h
+++ b/py/objmodule.h
@@ -34,4 +34,13 @@ extern const mp_map_t mp_builtin_module_weak_links_map;
mp_obj_t mp_module_get(qstr module_name);
void mp_module_register(qstr qstr, mp_obj_t module);
+#if MICROPY_MODULE_BUILTIN_INIT
+void mp_module_call_init(qstr module_name, mp_obj_t module_obj);
+#else
+static inline void mp_module_call_init(qstr module_name, mp_obj_t module_obj) {
+ (void)module_name;
+ (void)module_obj;
+}
+#endif
+
#endif // MICROPY_INCLUDED_PY_OBJMODULE_H
diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c
index 2288fa7b6..832a4a671 100644
--- a/py/objnamedtuple.c
+++ b/py/objnamedtuple.c
@@ -27,15 +27,14 @@
#include <string.h>
-#include "py/nlr.h"
-#include "py/objnamedtuple.h"
#include "py/objtuple.h"
#include "py/runtime.h"
#include "py/objstr.h"
+#include "py/objnamedtuple.h"
#if MICROPY_PY_COLLECTIONS
-STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) {
+size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name) {
for (size_t i = 0; i < type->n_fields; i++) {
if (type->fields[i] == name) {
return i;
@@ -44,7 +43,24 @@ STATIC size_t namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr n
return (size_t)-1;
}
-void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+#if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT
+STATIC mp_obj_t namedtuple_asdict(mp_obj_t self_in) {
+ mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in);
+ const qstr *fields = ((mp_obj_namedtuple_type_t*)self->tuple.base.type)->fields;
+ mp_obj_t dict = mp_obj_new_dict(self->tuple.len);
+ //make it an OrderedDict
+ mp_obj_dict_t *dictObj = MP_OBJ_TO_PTR(dict);
+ dictObj->base.type = &mp_type_ordereddict;
+ dictObj->map.is_ordered = 1;
+ for (size_t i = 0; i < self->tuple.len; ++i) {
+ mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(fields[i]), self->tuple.items[i]);
+ }
+ return dict;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict);
+#endif
+
+STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in);
mp_printf(print, "%q", o->tuple.base.type->name);
@@ -52,11 +68,18 @@ void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t ki
mp_obj_attrtuple_print_helper(print, fields, &o->tuple);
}
-void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (dest[0] == MP_OBJ_NULL) {
// load attribute
mp_obj_namedtuple_t *self = MP_OBJ_TO_PTR(self_in);
- size_t id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
+ #if MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT
+ if (attr == MP_QSTR__asdict) {
+ dest[0] = MP_OBJ_FROM_PTR(&namedtuple_asdict_obj);
+ dest[1] = self_in;
+ return;
+ }
+ #endif
+ size_t id = mp_obj_namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr);
if (id == (size_t)-1) {
return;
}
@@ -96,7 +119,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t
memset(&tuple->items[n_args], 0, sizeof(mp_obj_t) * n_kw);
for (size_t i = n_args; i < n_args + 2 * n_kw; i += 2) {
qstr kw = mp_obj_str_get_qstr(args[i]);
- size_t id = namedtuple_find_field(type, kw);
+ size_t id = mp_obj_namedtuple_find_field(type, kw);
if (id == (size_t)-1) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_arg_error_terse_mismatch();
@@ -119,9 +142,18 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t
return MP_OBJ_FROM_PTR(tuple);
}
-STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) {
+mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields) {
mp_obj_namedtuple_type_t *o = m_new_obj_var(mp_obj_namedtuple_type_t, qstr, n_fields);
memset(&o->base, 0, sizeof(o->base));
+ o->n_fields = n_fields;
+ for (size_t i = 0; i < n_fields; i++) {
+ o->fields[i] = mp_obj_str_get_qstr(fields[i]);
+ }
+ return o;
+}
+
+STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t *fields) {
+ mp_obj_namedtuple_type_t *o = mp_obj_new_namedtuple_base(n_fields, fields);
o->base.base.type = &mp_type_type;
o->base.name = name;
o->base.print = namedtuple_print;
@@ -132,10 +164,6 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, size_t n_fields, mp_obj_t
o->base.subscr = mp_obj_tuple_subscr;
o->base.getiter = mp_obj_tuple_getiter;
o->base.parent = &mp_type_tuple;
- o->n_fields = n_fields;
- for (size_t i = 0; i < n_fields; i++) {
- o->fields[i] = mp_obj_str_get_qstr(fields[i]);
- }
return MP_OBJ_FROM_PTR(o);
}
diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h
index a36404b8d..d32af35af 100644
--- a/py/objnamedtuple.h
+++ b/py/objnamedtuple.h
@@ -1,10 +1,9 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2014-2017 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,22 +23,14 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
#ifndef MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H
#define MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H
-#include <string.h>
-
-#include "py/nlr.h"
#include "py/objtuple.h"
-#include "py/runtime.h"
-#include "py/objstr.h"
-
-#if MICROPY_PY_COLLECTIONS
typedef struct _mp_obj_namedtuple_type_t {
mp_obj_type_t base;
- mp_uint_t n_fields;
+ size_t n_fields;
qstr fields[];
} mp_obj_namedtuple_type_t;
@@ -47,12 +38,7 @@ typedef struct _mp_obj_namedtuple_t {
mp_obj_tuple_t tuple;
} mp_obj_namedtuple_t;
-void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
-
-void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
-
-mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
-
-#endif // MICROPY_PY_COLLECTIONS
+size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name);
+mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields);
-#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H
+#endif // MICROPY_INCLUDED_PY_OBJNAMEDTUPLE_H
diff --git a/py/objobject.c b/py/objobject.c
index 49d2ec62e..265fcfbf2 100644
--- a/py/objobject.c
+++ b/py/objobject.c
@@ -52,9 +52,12 @@ STATIC mp_obj_t object___new__(mp_obj_t cls) {
if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) {
mp_raise_TypeError("__new__ arg must be a user-type");
}
- mp_obj_t o = MP_OBJ_SENTINEL;
- mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o);
- return res;
+ // This executes only "__new__" part of instance creation.
+ // TODO: This won't work well for classes with native bases.
+ // TODO: This is a hack, should be resolved along the lines of
+ // https://github.com/micropython/micropython/issues/606#issuecomment-43685883
+ const mp_obj_type_t *native_base;
+ return MP_OBJ_FROM_PTR(mp_obj_new_instance(MP_OBJ_TO_PTR(cls), &native_base));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___new___fun_obj, object___new__);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(object___new___obj, MP_ROM_PTR(&object___new___fun_obj));
diff --git a/py/objrange.c b/py/objrange.c
index 3874adb11..86aa0ccfe 100644
--- a/py/objrange.c
+++ b/py/objrange.c
@@ -138,6 +138,24 @@ STATIC mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
+#if MICROPY_PY_BUILTINS_RANGE_BINOP
+STATIC mp_obj_t range_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ if (!MP_OBJ_IS_TYPE(rhs_in, &mp_type_range) || op != MP_BINARY_OP_EQUAL) {
+ return MP_OBJ_NULL; // op not supported
+ }
+ mp_obj_range_t *lhs = MP_OBJ_TO_PTR(lhs_in);
+ mp_obj_range_t *rhs = MP_OBJ_TO_PTR(rhs_in);
+ mp_int_t lhs_len = range_len(lhs);
+ mp_int_t rhs_len = range_len(rhs);
+ return mp_obj_new_bool(
+ lhs_len == rhs_len
+ && (lhs_len == 0
+ || (lhs->start == rhs->start
+ && (lhs_len == 1 || lhs->step == rhs->step)))
+ );
+}
+#endif
+
STATIC mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) {
// load
@@ -195,6 +213,9 @@ const mp_obj_type_t mp_type_range = {
.print = range_print,
.make_new = range_make_new,
.unary_op = range_unary_op,
+ #if MICROPY_PY_BUILTINS_RANGE_BINOP
+ .binary_op = range_binary_op,
+ #endif
.subscr = range_subscr,
.getiter = range_getiter,
#if MICROPY_PY_BUILTINS_RANGE_ATTRS
diff --git a/py/objset.c b/py/objset.c
index 6ed15c791..799ba9df0 100644
--- a/py/objset.c
+++ b/py/objset.c
@@ -351,11 +351,9 @@ STATIC mp_obj_t set_issuperset_proper(mp_obj_t self_in, mp_obj_t other_in) {
}
STATIC mp_obj_t set_equal(mp_obj_t self_in, mp_obj_t other_in) {
+ assert(is_set_or_frozenset(other_in));
check_set_or_frozenset(self_in);
mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in);
- if (!is_set_or_frozenset(other_in)) {
- return mp_const_false;
- }
mp_obj_set_t *other = MP_OBJ_TO_PTR(other_in);
if (self->set.used != other->set.used) {
return mp_const_false;
@@ -461,7 +459,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
#else
bool update = true;
#endif
- if (op != MP_BINARY_OP_IN && !is_set_or_frozenset(rhs)) {
+ if (op != MP_BINARY_OP_CONTAINS && !is_set_or_frozenset(rhs)) {
// For all ops except containment the RHS must be a set/frozenset
return MP_OBJ_NULL;
}
@@ -507,7 +505,7 @@ STATIC mp_obj_t set_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
return set_issubset(lhs, rhs);
case MP_BINARY_OP_MORE_EQUAL:
return set_issuperset(lhs, rhs);
- case MP_BINARY_OP_IN: {
+ case MP_BINARY_OP_CONTAINS: {
mp_obj_set_t *o = MP_OBJ_TO_PTR(lhs);
mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP);
return mp_obj_new_bool(elem != MP_OBJ_NULL);
diff --git a/py/objstr.c b/py/objstr.c
index 7ace1cf73..aae5301ec 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -164,7 +164,14 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
mp_raise_msg(&mp_type_UnicodeError, NULL);
}
#endif
- mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len));
+
+ // Check if a qstr with this data already exists
+ qstr q = qstr_find_strn((const char*)str_data, str_len);
+ if (q != MP_QSTR_NULL) {
+ return MP_OBJ_NEW_QSTR(q);
+ }
+
+ mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(type, NULL, str_len));
o->data = str_data;
o->hash = str_hash;
return MP_OBJ_FROM_PTR(o);
@@ -176,7 +183,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
mp_raise_msg(&mp_type_UnicodeError, NULL);
}
#endif
- return mp_obj_new_str(bufinfo.buf, bufinfo.len, false);
+ return mp_obj_new_str(bufinfo.buf, bufinfo.len);
}
}
}
@@ -205,7 +212,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
if (str_hash == 0) {
str_hash = qstr_compute_hash(str_data, str_len);
}
- mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len));
+ mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_copy(&mp_type_bytes, NULL, str_len));
o->data = str_data;
o->hash = str_hash;
return MP_OBJ_FROM_PTR(o);
@@ -216,7 +223,10 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
}
if (MP_OBJ_IS_SMALL_INT(args[0])) {
- uint len = MP_OBJ_SMALL_INT_VALUE(args[0]);
+ mp_int_t len = MP_OBJ_SMALL_INT_VALUE(args[0]);
+ if (len < 0) {
+ mp_raise_ValueError(NULL);
+ }
vstr_t vstr;
vstr_init_len(&vstr, len);
memset(vstr.buf, 0, len);
@@ -226,7 +236,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size
// check if argument has the buffer protocol
mp_buffer_info_t bufinfo;
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
- return mp_obj_new_str_of_type(&mp_type_bytes, bufinfo.buf, bufinfo.len);
+ return mp_obj_new_bytes(bufinfo.buf, bufinfo.len);
}
vstr_t vstr;
@@ -377,8 +387,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
return mp_obj_new_str_from_vstr(lhs_type, &vstr);
}
- case MP_BINARY_OP_IN:
- /* NOTE `a in b` is `b.__contains__(a)` */
+ case MP_BINARY_OP_CONTAINS:
return mp_obj_new_bool(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len, 1) != NULL);
//case MP_BINARY_OP_NOT_EQUAL: // This is never passed here
@@ -423,7 +432,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) {
return MP_OBJ_NEW_SMALL_INT(self_data[index_val]);
} else {
- return mp_obj_new_str((char*)&self_data[index_val], 1, true);
+ return mp_obj_new_str_via_qstr((char*)&self_data[index_val], 1);
}
} else {
return MP_OBJ_NULL; // op not supported
@@ -654,9 +663,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) {
}
res->items[idx--] = mp_obj_new_str_of_type(self_type, s + sep_len, last - s - sep_len);
last = s;
- if (splits > 0) {
- splits--;
- }
+ splits--;
}
if (idx != 0) {
// We split less parts than split limit, now go cleanup surplus
@@ -1050,7 +1057,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
} else {
const char *lookup;
for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++);
- mp_obj_t field_q = mp_obj_new_str(field_name, lookup - field_name, true/*?*/);
+ mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr?
field_name = lookup;
mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP);
if (key_elem == NULL) {
@@ -1417,7 +1424,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
}
++str;
}
- mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true);
+ mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key);
arg = mp_obj_dict_get(dict, k_obj);
str++;
}
@@ -1702,7 +1709,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) {
// if needle_len is zero then we count each gap between characters as an occurrence
if (needle_len == 0) {
- return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char*)start, end - start) + 1);
+ return MP_OBJ_NEW_SMALL_INT(utf8_charlen(start, end - start) + 1);
}
// count the occurrences
@@ -1981,8 +1988,9 @@ const mp_obj_type_t mp_type_bytes = {
const mp_obj_str_t mp_const_empty_bytes_obj = {{&mp_type_bytes}, 0, 0, (const byte*)""};
// Create a str/bytes object using the given data. New memory is allocated and
-// the data is copied across.
-mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) {
+// the data is copied across. This function should only be used if the type is bytes,
+// or if the type is str and the string data is known to be not interned.
+mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len) {
mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
o->base.type = type;
o->len = len;
@@ -1996,6 +2004,22 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz
return MP_OBJ_FROM_PTR(o);
}
+// Create a str/bytes object using the given data. If the type is str and the string
+// data is already interned, then a qstr object is returned. Otherwise new memory is
+// allocated for the object and the data is copied across.
+mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len) {
+ if (type == &mp_type_str) {
+ return mp_obj_new_str((const char*)data, len);
+ } else {
+ return mp_obj_new_bytes(data, len);
+ }
+}
+
+// Create a str using a qstr to store the data; may use existing or new qstr.
+mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) {
+ return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));
+}
+
// Create a str/bytes object from the given vstr. The vstr buffer is resized to
// the exact length required and then reused for the str/bytes object. The vstr
// is cleared and can safely be passed to vstr_free if it was heap allocated.
@@ -2026,29 +2050,30 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) {
return MP_OBJ_FROM_PTR(o);
}
-mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already) {
- if (make_qstr_if_not_already) {
- // use existing, or make a new qstr
- return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len));
+mp_obj_t mp_obj_new_str(const char* data, size_t len) {
+ qstr q = qstr_find_strn(data, len);
+ if (q != MP_QSTR_NULL) {
+ // qstr with this data already exists
+ return MP_OBJ_NEW_QSTR(q);
} else {
- qstr q = qstr_find_strn(data, len);
- if (q != MP_QSTR_NULL) {
- // qstr with this data already exists
- return MP_OBJ_NEW_QSTR(q);
- } else {
- // no existing qstr, don't make one
- return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len);
- }
+ // no existing qstr, don't make one
+ return mp_obj_new_str_copy(&mp_type_str, (const byte*)data, len);
}
}
mp_obj_t mp_obj_str_intern(mp_obj_t str) {
GET_STR_DATA_LEN(str, data, len);
- return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len));
+ return mp_obj_new_str_via_qstr((const char*)data, len);
+}
+
+mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) {
+ size_t len;
+ const char *data = mp_obj_str_get_data(obj, &len);
+ return mp_obj_new_str_via_qstr((const char*)data, len);
}
mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) {
- return mp_obj_new_str_of_type(&mp_type_bytes, data, len);
+ return mp_obj_new_str_copy(&mp_type_bytes, data, len);
}
bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
@@ -2070,7 +2095,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
}
}
-STATIC void bad_implicit_conversion(mp_obj_t self_in) {
+STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_TypeError("can't convert to str implicitly");
} else {
@@ -2142,7 +2167,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in);
GET_STR_DATA_LEN(self->str, str, len);
if (self->cur < len) {
- mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true);
+ mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)str + self->cur, 1);
self->cur += 1;
return o_out;
} else {
diff --git a/py/objstr.h b/py/objstr.h
index 82501a763..4e55cad09 100644
--- a/py/objstr.h
+++ b/py/objstr.h
@@ -65,6 +65,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t
void mp_str_print_json(const mp_print_t *print, const byte *str_data, size_t str_len);
mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args);
+mp_obj_t mp_obj_new_str_copy(const mp_obj_type_t *type, const byte* data, size_t len);
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, size_t len);
mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);
diff --git a/py/objstringio.c b/py/objstringio.c
index 5c50aa317..b405ee21e 100644
--- a/py/objstringio.c
+++ b/py/objstringio.c
@@ -143,6 +143,17 @@ STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
}
case MP_STREAM_FLUSH:
return 0;
+ case MP_STREAM_CLOSE:
+ #if MICROPY_CPYTHON_COMPAT
+ vstr_free(o->vstr);
+ o->vstr = NULL;
+ #else
+ vstr_clear(o->vstr);
+ o->vstr->alloc = 0;
+ o->vstr->len = 0;
+ o->pos = 0;
+ #endif
+ return 0;
default:
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
@@ -159,24 +170,9 @@ STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
-STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
- mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
-#if MICROPY_CPYTHON_COMPAT
- vstr_free(self->vstr);
- self->vstr = NULL;
-#else
- vstr_clear(self->vstr);
- self->vstr->alloc = 0;
- self->vstr->len = 0;
- self->pos = 0;
-#endif
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);
-
STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
- return stringio_close(args[0]);
+ return mp_stream_close(args[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
@@ -233,7 +229,7 @@ STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) },
diff --git a/py/objstrunicode.c b/py/objstrunicode.c
index a243022a7..ca41a7baa 100644
--- a/py/objstrunicode.c
+++ b/py/objstrunicode.c
@@ -104,7 +104,7 @@ STATIC mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
case MP_UNARY_OP_BOOL:
return mp_obj_new_bool(str_len != 0);
case MP_UNARY_OP_LEN:
- return MP_OBJ_NEW_SMALL_INT(unichar_charlen((const char *)str_data, str_len));
+ return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len));
default:
return MP_OBJ_NULL; // op not supported
}
@@ -216,7 +216,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
++len;
}
}
- return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string
+ return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string
} else {
return MP_OBJ_NULL; // op not supported
}
@@ -291,7 +291,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) {
if (self->cur < len) {
const byte *cur = str + self->cur;
const byte *end = utf8_next_char(str + self->cur);
- mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true);
+ mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur);
self->cur += end - cur;
return o_out;
} else {
diff --git a/py/objtype.c b/py/objtype.c
index 5b70e8e48..dc9724e5b 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2018 Damien P. George
* Copyright (c) 2014-2016 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -42,19 +42,17 @@
#define DEBUG_printf(...) (void)0
#endif
+#define ENABLE_SPECIAL_ACCESSORS \
+ (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY)
+
+#define TYPE_FLAG_IS_SUBCLASSED (0x0001)
+#define TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002)
+
STATIC mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
/******************************************************************************/
// instance object
-STATIC mp_obj_t mp_obj_new_instance(const mp_obj_type_t *class, size_t subobjs) {
- mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
- o->base.type = class;
- mp_map_init(&o->members, 0);
- mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj));
- return MP_OBJ_FROM_PTR(o);
-}
-
STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
int count = 0;
for (;;) {
@@ -68,6 +66,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
} else if (type->parent == NULL) {
// No parents so end search here.
return count;
+ #if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
// Multiple parents, search through them all recursively.
const mp_obj_tuple_t *parent_tuple = type->parent;
@@ -79,6 +78,7 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
count += instance_count_native_bases(bt, last_native_base);
}
return count;
+ #endif
} else {
// A single parent, use iteration to continue the search.
type = type->parent;
@@ -86,6 +86,35 @@ STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t
}
}
+// This wrapper function is allows a subclass of a native type to call the
+// __init__() method (corresponding to type->make_new) of the native type.
+STATIC mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *args) {
+ mp_obj_instance_t *self = MP_OBJ_TO_PTR(args[0]);
+ const mp_obj_type_t *native_base = NULL;
+ instance_count_native_bases(self->base.type, &native_base);
+ self->subobj[0] = native_base->make_new(native_base, n_args - 1, 0, args + 1);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(native_base_init_wrapper_obj, 1, MP_OBJ_FUN_ARGS_MAX, native_base_init_wrapper);
+
+#if !MICROPY_CPYTHON_COMPAT
+STATIC
+#endif
+mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *class, const mp_obj_type_t **native_base) {
+ size_t num_native_bases = instance_count_native_bases(class, native_base);
+ assert(num_native_bases < 2);
+ mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, num_native_bases);
+ o->base.type = class;
+ mp_map_init(&o->members, 0);
+ // Initialise the native base-class slot (should be 1 at most) with a valid
+ // object. It doesn't matter which object, so long as it can be uniquely
+ // distinguished from a native class that is initialised.
+ if (num_native_bases != 0) {
+ o->subobj[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
+ }
+ return o;
+}
+
// TODO
// This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO
// http://python-history.blogspot.com/2010/06/method-resolution-order.html
@@ -176,6 +205,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
if (type->parent == NULL) {
DEBUG_printf("mp_obj_class_lookup: No more parents\n");
return;
+ #if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = type->parent;
const mp_obj_t *item = parent_tuple->items;
@@ -196,6 +226,7 @@ STATIC void mp_obj_class_lookup(struct class_lookup_data *lookup, const mp_obj_
// search last base (simple tail recursion elimination)
assert(MP_OBJ_IS_TYPE(*item, &mp_type_type));
type = (mp_obj_type_t*)MP_OBJ_TO_PTR(*item);
+ #endif
} else {
type = type->parent;
}
@@ -251,20 +282,6 @@ STATIC void instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) {
assert(mp_obj_is_instance_type(self));
- const mp_obj_type_t *native_base;
- size_t num_native_bases = instance_count_native_bases(self, &native_base);
- assert(num_native_bases < 2);
-
- mp_obj_instance_t *o = MP_OBJ_TO_PTR(mp_obj_new_instance(self, num_native_bases));
-
- // This executes only "__new__" part of instance creation.
- // TODO: This won't work well for classes with native bases.
- // TODO: This is a hack, should be resolved along the lines of
- // https://github.com/micropython/micropython/issues/606#issuecomment-43685883
- if (n_args == 1 && *args == MP_OBJ_SENTINEL) {
- return MP_OBJ_FROM_PTR(o);
- }
-
// look for __new__ function
mp_obj_t init_fn[2] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
@@ -276,13 +293,22 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
};
mp_obj_class_lookup(&lookup, self);
- mp_obj_t new_ret = MP_OBJ_FROM_PTR(o);
- if (init_fn[0] == MP_OBJ_SENTINEL) {
- // Native type's constructor is what wins - it gets all our arguments,
- // and none Python classes are initialized at all.
- o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args);
- } else if (init_fn[0] != MP_OBJ_NULL) {
- // now call Python class __new__ function with all args
+ const mp_obj_type_t *native_base = NULL;
+ mp_obj_instance_t *o;
+ if (init_fn[0] == MP_OBJ_NULL || init_fn[0] == MP_OBJ_SENTINEL) {
+ // Either there is no __new__() method defined or there is a native
+ // constructor. In both cases create a blank instance.
+ o = mp_obj_new_instance(self, &native_base);
+
+ // Since type->make_new() implements both __new__() and __init__() in
+ // one go, of which the latter may be overridden by the Python subclass,
+ // we defer (see the end of this function) the call of the native
+ // constructor to give a chance for the Python __init__() method to call
+ // said native constructor.
+
+ } else {
+ // Call Python class __new__ function with all args to create an instance
+ mp_obj_t new_ret;
if (n_args == 0 && n_kw == 0) {
mp_obj_t args2[1] = {MP_OBJ_FROM_PTR(self)};
new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, args2);
@@ -294,17 +320,20 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
}
- }
+ // https://docs.python.org/3.4/reference/datamodel.html#object.__new__
+ // "If __new__() does not return an instance of cls, then the new
+ // instance's __init__() method will not be invoked."
+ if (mp_obj_get_type(new_ret) != self) {
+ return new_ret;
+ }
- // https://docs.python.org/3.4/reference/datamodel.html#object.__new__
- // "If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked."
- if (mp_obj_get_type(new_ret) != self) {
- return new_ret;
+ // The instance returned by __new__() becomes the new object
+ o = MP_OBJ_TO_PTR(new_ret);
}
- o = MP_OBJ_TO_PTR(new_ret);
-
// now call Python class __init__ function with all args
+ // This method has a chance to call super().__init__() to construct a
+ // possible native base class.
init_fn[0] = init_fn[1] = MP_OBJ_NULL;
lookup.obj = o;
lookup.attr = MP_QSTR___init__;
@@ -333,6 +362,12 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
}
+ // If the type had a native base that was not explicitly initialised
+ // (constructed) by the Python __init__() method then construct it now.
+ if (native_base != NULL && o->subobj[0] == MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj)) {
+ o->subobj[0] = native_base->make_new(native_base, n_args, n_kw, args);
+ }
+
return MP_OBJ_FROM_PTR(o);
}
@@ -424,7 +459,7 @@ const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
[MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
[MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
// MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
- [MP_BINARY_OP_IN] = MP_QSTR___contains__,
+ [MP_BINARY_OP_CONTAINS] = MP_QSTR___contains__,
// All inplace methods are optional, and normal methods will be used
// as a fallback.
@@ -537,7 +572,6 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
if (elem != NULL) {
// object member, always treated as a value
- // TODO should we check for properties?
dest[0] = elem->value;
return;
}
@@ -568,6 +602,11 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
mp_obj_t member = dest[0];
if (member != MP_OBJ_NULL) {
// changes here may may require changes to super_attr, below
+ if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
+ // Class doesn't have any special accessors to check so return straightaway
+ return;
+ }
+
#if MICROPY_PY_BUILTINS_PROPERTY
if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
// object member is a property; delegate the load to the property
@@ -629,11 +668,15 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(self_in);
+ if (!(self->base.type->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
+ // Class doesn't have any special accessors so skip their checks
+ goto skip_special_accessors;
+ }
+
#if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS
// With property and/or descriptors enabled we need to do a lookup
// first in the class dict for the attribute to see if the store should
// be delegated.
- // Note: this makes all stores slow... how to fix?
mp_obj_t member[2] = {MP_OBJ_NULL};
struct class_lookup_data lookup = {
.obj = self,
@@ -705,9 +748,9 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
}
#endif
+ #if MICROPY_PY_DELATTR_SETATTR
if (value == MP_OBJ_NULL) {
// delete attribute
- #if MICROPY_PY_DELATTR_SETATTR
// try __delattr__ first
mp_obj_t attr_delattr_method[3];
mp_load_method_maybe(self_in, MP_QSTR___delattr__, attr_delattr_method);
@@ -717,13 +760,8 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
mp_call_method_n_kw(1, 0, attr_delattr_method);
return true;
}
- #endif
-
- mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
- return elem != NULL;
} else {
// store attribute
- #if MICROPY_PY_DELATTR_SETATTR
// try __setattr__ first
mp_obj_t attr_setattr_method[4];
mp_load_method_maybe(self_in, MP_QSTR___setattr__, attr_setattr_method);
@@ -734,14 +772,23 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
mp_call_method_n_kw(2, 0, attr_setattr_method);
return true;
}
- #endif
+ }
+ #endif
+skip_special_accessors:
+
+ if (value == MP_OBJ_NULL) {
+ // delete attribute
+ mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
+ return elem != NULL;
+ } else {
+ // store attribute
mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
return true;
}
}
-void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+STATIC void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (dest[0] == MP_OBJ_NULL) {
mp_obj_instance_load_attr(self_in, attr, dest);
} else {
@@ -876,6 +923,34 @@ STATIC mp_int_t instance_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
// - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
// - creating a new class (a new type) creates a new mp_obj_type_t
+#if ENABLE_SPECIAL_ACCESSORS
+STATIC bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
+ #if MICROPY_PY_DELATTR_SETATTR
+ if (key == MP_OBJ_NEW_QSTR(MP_QSTR___setattr__) || key == MP_OBJ_NEW_QSTR(MP_QSTR___delattr__)) {
+ return true;
+ }
+ #endif
+ #if MICROPY_PY_BUILTINS_PROPERTY
+ if (MP_OBJ_IS_TYPE(value, &mp_type_property)) {
+ return true;
+ }
+ #endif
+ #if MICROPY_PY_DESCRIPTORS
+ static const uint8_t to_check[] = {
+ MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__,
+ };
+ for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) {
+ mp_obj_t dest_temp[2];
+ mp_load_method_protected(value, to_check[i], dest_temp, true);
+ if (dest_temp[0] != MP_OBJ_NULL) {
+ return true;
+ }
+ }
+ #endif
+ return false;
+}
+#endif
+
STATIC void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
@@ -950,21 +1025,34 @@ STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
if (self->locals_dict != NULL) {
assert(self->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now
mp_map_t *locals_map = &self->locals_dict->map;
+ if (locals_map->is_fixed) {
+ // can't apply delete/store to a fixed map
+ return;
+ }
if (dest[1] == MP_OBJ_NULL) {
// delete attribute
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
- // note that locals_map may be in ROM, so remove will fail in that case
if (elem != NULL) {
dest[0] = MP_OBJ_NULL; // indicate success
}
} else {
+ #if ENABLE_SPECIAL_ACCESSORS
+ // Check if we add any special accessor methods with this store
+ if (!(self->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
+ if (check_for_special_accessors(MP_OBJ_NEW_QSTR(attr), dest[1])) {
+ if (self->flags & TYPE_FLAG_IS_SUBCLASSED) {
+ // This class is already subclassed so can't have special accessors added
+ mp_raise_msg(&mp_type_AttributeError, "can't add special method to already-subclassed class");
+ }
+ self->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
+ }
+ }
+ #endif
+
// store attribute
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
- // note that locals_map may be in ROM, so add will fail in that case
- if (elem != NULL) {
- elem->value = make_obj_long_lived(dest[1], 10);
- dest[0] = MP_OBJ_NULL; // indicate success
- }
+ elem->value = make_obj_long_lived(dest[1], 10);
+ dest[0] = MP_OBJ_NULL; // indicate success
}
}
}
@@ -981,26 +1069,26 @@ const mp_obj_type_t mp_type_type = {
};
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
- if(!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) {
- // MicroPython restriction, for now
- mp_raise_TypeError("type() argument 2 must be tuple");
+ // Verify input objects have expected type
+ if (!MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)) {
+ mp_raise_TypeError(NULL);
}
- if(!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) {
- // MicroPython restriction, for now
- mp_raise_TypeError("type() argument 3 must be dict");
+ if (!MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)) {
+ mp_raise_TypeError(NULL);
}
// TODO might need to make a copy of locals_dict; at least that's how CPython does it
// Basic validation of base classes
- size_t len;
- mp_obj_t *items;
- mp_obj_tuple_get(bases_tuple, &len, &items);
- for (size_t i = 0; i < len; i++) {
- if(!MP_OBJ_IS_TYPE(items[i], &mp_type_type)) {
+ uint16_t base_flags = 0;
+ size_t bases_len;
+ mp_obj_t *bases_items;
+ mp_obj_tuple_get(bases_tuple, &bases_len, &bases_items);
+ for (size_t i = 0; i < bases_len; i++) {
+ if (!MP_OBJ_IS_TYPE(bases_items[i], &mp_type_type)) {
mp_raise_TypeError("type is not an acceptable base type");
}
- mp_obj_type_t *t = MP_OBJ_TO_PTR(items[i]);
+ mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
// TODO: Verify with CPy, tested on function type
if (t->make_new == NULL) {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
@@ -1010,10 +1098,17 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
"type '%q' is not an acceptable base type", t->name);
}
}
+ #if ENABLE_SPECIAL_ACCESSORS
+ if (mp_obj_is_instance_type(t)) {
+ t->flags |= TYPE_FLAG_IS_SUBCLASSED;
+ base_flags |= t->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
+ }
+ #endif
}
mp_obj_type_t *o = m_new0_ll(mp_obj_type_t, 1);
o->base.type = &mp_type_type;
+ o->flags = base_flags;
o->name = name;
o->print = instance_print;
o->make_new = mp_obj_instance_make_new;
@@ -1026,22 +1121,41 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
//o->iternext = ; not implemented
o->buffer_p.get_buffer = instance_get_buffer;
- if (len > 0) {
+ if (bases_len > 0) {
// Inherit protocol from a base class. This allows to define an
// abstract base class which would translate C-level protocol to
// Python method calls, and any subclass inheriting from it will
// support this feature.
- o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(items[0]))->protocol;
+ o->protocol = ((mp_obj_type_t*)MP_OBJ_TO_PTR(bases_items[0]))->protocol;
- if (len >= 2) {
+ if (bases_len >= 2) {
+ #if MICROPY_MULTIPLE_INHERITANCE
o->parent = MP_OBJ_TO_PTR(bases_tuple);
+ #else
+ mp_raise_NotImplementedError("multiple inheritance not supported");
+ #endif
} else {
- o->parent = MP_OBJ_TO_PTR(items[0]);
+ o->parent = MP_OBJ_TO_PTR(bases_items[0]);
}
}
o->locals_dict = make_dict_long_lived(locals_dict, 10);
+ #if ENABLE_SPECIAL_ACCESSORS
+ // Check if the class has any special accessor methods
+ if (!(o->flags & TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) {
+ for (size_t i = 0; i < o->locals_dict->map.alloc; i++) {
+ if (MP_MAP_SLOT_IS_FILLED(&o->locals_dict->map, i)) {
+ const mp_map_elem_t *elem = &o->locals_dict->map.table[i];
+ if (check_for_special_accessors(elem->key, elem->value)) {
+ o->flags |= TYPE_FLAG_HAS_SPECIAL_ACCESSORS;
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
const mp_obj_type_t *native_base;
size_t num_native_bases = instance_count_native_bases(o, &native_base);
if (num_native_bases > 1) {
@@ -1114,49 +1228,69 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
.is_type = false,
};
+ // Allow a call super().__init__() to reach any native base classes
+ if (attr == MP_QSTR___init__) {
+ lookup.meth_offset = offsetof(mp_obj_type_t, make_new);
+ }
+
if (type->parent == NULL) {
// no parents, do nothing
+ #if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t*)type->parent)->type == &mp_type_tuple) {
const mp_obj_tuple_t *parent_tuple = type->parent;
size_t len = parent_tuple->len;
const mp_obj_t *items = parent_tuple->items;
for (size_t i = 0; i < len; i++) {
assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
+ if (MP_OBJ_TO_PTR(items[i]) == &mp_type_object) {
+ // The "object" type will be searched at the end of this function,
+ // and we don't want to lookup native methods in object.
+ continue;
+ }
mp_obj_class_lookup(&lookup, (mp_obj_type_t*)MP_OBJ_TO_PTR(items[i]));
if (dest[0] != MP_OBJ_NULL) {
break;
}
}
- } else {
+ #endif
+ } else if (type->parent != &mp_type_object) {
mp_obj_class_lookup(&lookup, type->parent);
}
if (dest[0] != MP_OBJ_NULL) {
- mp_obj_t member = dest[0];
- // changes to mp_obj_instance_load_attr may require changes
- // here...
- #if MICROPY_PY_BUILTINS_PROPERTY
- if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
- const mp_obj_t *proxy = mp_obj_property_get(member);
- if (proxy[0] == mp_const_none) {
- mp_raise_AttributeError("unreadable attribute");
- } else {
- dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
+ if (dest[0] == MP_OBJ_SENTINEL) {
+ // Looked up native __init__ so defer to it
+ dest[0] = MP_OBJ_FROM_PTR(&native_base_init_wrapper_obj);
+ dest[1] = self->obj;
+ } else {
+ mp_obj_t member = dest[0];
+ // changes to mp_obj_instance_load_attr may require changes
+ // here...
+ #if MICROPY_PY_BUILTINS_PROPERTY
+ if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
+ const mp_obj_t *proxy = mp_obj_property_get(member);
+ if (proxy[0] == mp_const_none) {
+ mp_raise_AttributeError("unreadable attribute");
+ } else {
+ dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
+ }
}
+ #endif
+ #if MICROPY_PY_DESCRIPTORS
+ mp_obj_t attr_get_method[4];
+ mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method);
+ if (attr_get_method[0] != MP_OBJ_NULL) {
+ attr_get_method[2] = self_in;
+ attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in));
+ dest[0] = mp_call_method_n_kw(2, 0, attr_get_method);
}
- #endif
- #if MICROPY_PY_DESCRIPTORS
- mp_obj_t attr_get_method[4];
- mp_load_method_maybe(member, MP_QSTR___get__, attr_get_method);
- if (attr_get_method[0] != MP_OBJ_NULL) {
- attr_get_method[2] = self_in;
- attr_get_method[3] = MP_OBJ_FROM_PTR(mp_obj_get_type(self_in));
- dest[0] = mp_call_method_n_kw(2, 0, attr_get_method);
- }
- #endif
return;
}
+ // Reset meth_offset so we don't look up any native methods in object,
+ // because object never takes up the native base-class slot.
+ lookup.meth_offset = 0;
+
mp_obj_class_lookup(&lookup, &mp_type_object);
}
@@ -1196,6 +1330,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
if (self->parent == NULL) {
// type has no parents
return false;
+ #if MICROPY_MULTIPLE_INHERITANCE
} else if (((mp_obj_base_t*)self->parent)->type == &mp_type_tuple) {
// get the base objects (they should be type objects)
const mp_obj_tuple_t *parent_tuple = self->parent;
@@ -1211,6 +1346,7 @@ bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
// search last base (simple tail recursion elimination)
object = *item;
+ #endif
} else {
// type has 1 parent
object = MP_OBJ_FROM_PTR(self->parent);
diff --git a/py/objtype.h b/py/objtype.h
index 52419f3cd..3fc8c6e1b 100644
--- a/py/objtype.h
+++ b/py/objtype.h
@@ -37,8 +37,10 @@ typedef struct _mp_obj_instance_t {
// TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them
} mp_obj_instance_t;
-// this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work
-void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
+#if MICROPY_CPYTHON_COMPAT
+// this is needed for object.__new__
+mp_obj_instance_t *mp_obj_new_instance(const mp_obj_type_t *cls, const mp_obj_type_t **native_base);
+#endif
// these need to be exposed so mp_obj_is_callable can work correctly
bool mp_obj_instance_is_callable(mp_obj_t self_in);
diff --git a/py/opmethods.c b/py/opmethods.c
index 1200ba39e..247fa5bbc 100644
--- a/py/opmethods.c
+++ b/py/opmethods.c
@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
-#include "py/runtime0.h"
+#include "py/obj.h"
#include "py/builtin.h"
STATIC mp_obj_t op_getitem(mp_obj_t self_in, mp_obj_t key_in) {
@@ -47,6 +47,6 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_op_delitem_obj, op_delitem);
STATIC mp_obj_t op_contains(mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_type_t *type = mp_obj_get_type(lhs_in);
- return type->binary_op(MP_BINARY_OP_IN, lhs_in, rhs_in);
+ return type->binary_op(MP_BINARY_OP_CONTAINS, lhs_in, rhs_in);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_op_contains_obj, op_contains);
diff --git a/py/parse.c b/py/parse.c
index 08a403401..ab162710d 100644
--- a/py/parse.c
+++ b/py/parse.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013-2015 Damien P. George
+ * Copyright (c) 2013-2017 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -58,15 +58,6 @@
// (un)comment to use rule names; for debugging
//#define USE_RULE_NAME (1)
-typedef struct _rule_t {
- byte rule_id;
- byte act;
-#ifdef USE_RULE_NAME
- const char *rule_name;
-#endif
- uint16_t arg[];
-} rule_t;
-
enum {
// define rules with a compile function
#define DEF_RULE(rule, comp, kind, ...) RULE_##rule,
@@ -84,6 +75,8 @@ enum {
#undef DEF_RULE_NC
};
+// Define an array of actions corresponding to each rule
+STATIC const uint8_t rule_act_table[] = {
#define or(n) (RULE_ACT_OR | n)
#define and(n) (RULE_ACT_AND | n)
#define and_ident(n) (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT)
@@ -91,44 +84,128 @@ enum {
#define one_or_more (RULE_ACT_LIST | 2)
#define list (RULE_ACT_LIST | 1)
#define list_with_end (RULE_ACT_LIST | 3)
-#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t)
-#define rule(r) (RULE_ARG_RULE | RULE_##r)
-#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r)
-#ifdef USE_RULE_NAME
-#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };
-#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };
-#else
-#define DEF_RULE(rule, comp, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } };
-#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, { __VA_ARGS__ } };
-#endif
+
+#define DEF_RULE(rule, comp, kind, ...) kind,
+#define DEF_RULE_NC(rule, kind, ...)
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+
+ 0, // RULE_const_object
+
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) kind,
#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+
#undef or
#undef and
+#undef and_ident
+#undef and_blank
+#undef one_or_more
#undef list
#undef list_with_end
+};
+
+// Define the argument data for each rule, as a combined array
+STATIC const uint16_t rule_arg_combined_table[] = {
+#define tok(t) (RULE_ARG_TOK | MP_TOKEN_##t)
+#define rule(r) (RULE_ARG_RULE | RULE_##r)
+#define opt_rule(r) (RULE_ARG_OPT_RULE | RULE_##r)
+
+#define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__,
+#define DEF_RULE_NC(rule, kind, ...)
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) __VA_ARGS__,
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+
#undef tok
#undef rule
#undef opt_rule
-#undef one_or_more
+};
+
+// Macro to create a list of N identifiers where N is the number of variable arguments to the macro
+#define RULE_EXPAND(x) x
+#define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule))
+#define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__))
+#define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) __VA_ARGS__
+#define RULE_PADDING_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r,
+
+// Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table
+enum {
+#define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__)
+#define DEF_RULE_NC(rule, kind, ...)
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__)
+#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
+};
-STATIC const rule_t *const rules[] = {
-// define rules with a compile function
-#define DEF_RULE(rule, comp, kind, ...) &rule_##rule,
+// Macro to compute the start of a rule in rule_arg_combined_table
+#define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule))
+#define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__))
+#define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) _13
+#define RULE_ARG_OFFSET_IDS(r) PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r,
+
+// Use the above enum values to create a table of offsets for each rule's arg
+// data, which indexes rule_arg_combined_table. The offsets require 9 bits of
+// storage but only the lower 8 bits are stored here. The 9th bit is computed
+// in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant.
+STATIC const uint8_t rule_arg_offset_table[] = {
+#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,
#define DEF_RULE_NC(rule, kind, ...)
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
- NULL, // RULE_const_object
+ 0, // RULE_const_object
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+};
-// define rules without a compile function
+// Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table
+static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 =
+#define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :
+#define DEF_RULE_NC(rule, kind, ...)
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+#define DEF_RULE(rule, comp, kind, ...)
+#define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+0;
+
+#if USE_RULE_NAME
+// Define an array of rule names corresponding to each rule
+STATIC const char *const rule_name_table[] = {
+#define DEF_RULE(rule, comp, kind, ...) #rule,
+#define DEF_RULE_NC(rule, kind, ...)
+#include "py/grammar.h"
+#undef DEF_RULE
+#undef DEF_RULE_NC
+ "", // RULE_const_object
#define DEF_RULE(rule, comp, kind, ...)
-#define DEF_RULE_NC(rule, kind, ...) &rule_##rule,
+#define DEF_RULE_NC(rule, kind, ...) #rule,
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
};
+#endif
typedef struct _rule_stack_t {
size_t src_line : 8 * sizeof(size_t) - 8; // maximum bits storing source line number
@@ -164,8 +241,17 @@ typedef struct _parser_t {
#endif
} parser_t;
+STATIC const uint16_t *get_rule_arg(uint8_t r_id) {
+ size_t off = rule_arg_offset_table[r_id];
+ if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) {
+ off |= 0x100;
+ }
+ return &rule_arg_combined_table[off];
+}
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
+
STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) {
// use a custom memory allocator to store parse nodes sequentially in large chunks
@@ -208,7 +294,7 @@ STATIC void *parser_alloc(parser_t *parser, size_t num_bytes) {
}
#pragma GCC diagnostic pop
-STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t arg_i) {
+STATIC void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) {
if (parser->rule_stack_top >= parser->rule_stack_alloc) {
rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC);
parser->rule_stack = rs;
@@ -216,21 +302,22 @@ STATIC void push_rule(parser_t *parser, size_t src_line, const rule_t *rule, siz
}
rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
rs->src_line = src_line;
- rs->rule_id = rule->rule_id;
+ rs->rule_id = rule_id;
rs->arg_i = arg_i;
}
STATIC void push_rule_from_arg(parser_t *parser, size_t arg) {
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
size_t rule_id = arg & RULE_ARG_ARG_MASK;
- push_rule(parser, parser->lexer->tok_line, rules[rule_id], 0);
+ push_rule(parser, parser->lexer->tok_line, rule_id, 0);
}
-STATIC void pop_rule(parser_t *parser, const rule_t **rule, size_t *arg_i, size_t *src_line) {
+STATIC uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) {
parser->rule_stack_top -= 1;
- *rule = rules[parser->rule_stack[parser->rule_stack_top].rule_id];
+ uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id;
*arg_i = parser->rule_stack[parser->rule_stack_top].arg_i;
*src_line = parser->rule_stack[parser->rule_stack_top].src_line;
+ return rule_id;
}
bool mp_parse_node_is_const_false(mp_parse_node_t pn) {
@@ -316,11 +403,11 @@ void mp_parse_node_print(mp_parse_node_t pn, size_t indent) {
#endif
} else {
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
-#ifdef USE_RULE_NAME
- printf("%s(%u) (n=%u)\n", rules[MP_PARSE_NODE_STRUCT_KIND(pns)]->rule_name, (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
-#else
+ #if USE_RULE_NAME
+ printf("%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
+ #else
printf("rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
-#endif
+ #endif
for (size_t i = 0; i < n; i++) {
mp_parse_node_print(pns->nodes[i], indent + 2);
}
@@ -372,7 +459,19 @@ STATIC mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line,
return (mp_parse_node_t)pn;
}
-STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
+STATIC mp_parse_node_t mp_parse_node_new_small_int_checked(parser_t *parser, mp_obj_t o_val) {
+ (void)parser;
+ mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_val);
+ #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
+ // A parse node is only 32-bits and the small-int value must fit in 31-bits
+ if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) {
+ return make_node_const_object(parser, 0, o_val);
+ }
+ #endif
+ return mp_parse_node_new_small_int(val);
+}
+
+STATIC void push_result_token(parser_t *parser, uint8_t rule_id) {
mp_parse_node_t pn;
mp_lexer_t *lex = parser->lexer;
if (lex->tok_kind == MP_TOKEN_NAME) {
@@ -380,10 +479,10 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
#if MICROPY_COMP_CONST
// if name is a standalone identifier, look it up in the table of dynamic constants
mp_map_elem_t *elem;
- if (rule->rule_id == RULE_atom
+ if (rule_id == RULE_atom
&& (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) {
if (MP_OBJ_IS_SMALL_INT(elem->value)) {
- pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(elem->value));
+ pn = mp_parse_node_new_small_int_checked(parser, elem->value);
} else {
pn = make_node_const_object(parser, lex->tok_line, elem->value);
}
@@ -391,13 +490,13 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);
}
#else
- (void)rule;
+ (void)rule_id;
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);
#endif
} else if (lex->tok_kind == MP_TOKEN_INTEGER) {
mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex);
if (MP_OBJ_IS_SMALL_INT(o)) {
- pn = mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(o));
+ pn = mp_parse_node_new_small_int_checked(parser, o);
} else {
pn = make_node_const_object(parser, lex->tok_line, o);
}
@@ -420,7 +519,7 @@ STATIC void push_result_token(parser_t *parser, const rule_t *rule) {
pn = mp_parse_node_new_leaf(lex->tok_kind == MP_TOKEN_STRING ? MP_PARSE_NODE_STRING : MP_PARSE_NODE_BYTES, qst);
} else {
// not interned, make a node holding a pointer to the string/bytes object
- mp_obj_t o = mp_obj_new_str_of_type(
+ mp_obj_t o = mp_obj_new_str_copy(
lex->tok_kind == MP_TOKEN_STRING ? &mp_type_str : &mp_type_bytes,
(const byte*)lex->vstr.buf, lex->vstr.len);
pn = make_node_const_object(parser, lex->tok_line, o);
@@ -445,12 +544,12 @@ STATIC const mp_rom_map_elem_t mp_constants_table[] = {
STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);
#endif
-STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args);
+STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args);
#if MICROPY_COMP_CONST_FOLDING
-STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t *num_args) {
- if (rule->rule_id == RULE_or_test
- || rule->rule_id == RULE_and_test) {
+STATIC bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) {
+ if (rule_id == RULE_or_test
+ || rule_id == RULE_and_test) {
// folding for binary logical ops: or and
size_t copy_to = *num_args;
for (size_t i = copy_to; i > 0;) {
@@ -460,7 +559,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t
// always need to keep the last value
break;
}
- if (rule->rule_id == RULE_or_test) {
+ if (rule_id == RULE_or_test) {
if (mp_parse_node_is_const_true(pn)) {
//
break;
@@ -487,7 +586,7 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t
// we did a complete folding if there's only 1 arg left
return *num_args == 1;
- } else if (rule->rule_id == RULE_not_test_2) {
+ } else if (rule_id == RULE_not_test_2) {
// folding for unary logical op: not
mp_parse_node_t pn = peek_result(parser, 0);
if (mp_parse_node_is_const_false(pn)) {
@@ -505,23 +604,23 @@ STATIC bool fold_logical_constants(parser_t *parser, const rule_t *rule, size_t
return false;
}
-STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args) {
+STATIC bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
// this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4
// it does not do partial folding, eg 1 + 2 + x -> 3 + x
mp_obj_t arg0;
- if (rule->rule_id == RULE_expr
- || rule->rule_id == RULE_xor_expr
- || rule->rule_id == RULE_and_expr) {
+ if (rule_id == RULE_expr
+ || rule_id == RULE_xor_expr
+ || rule_id == RULE_and_expr) {
// folding for binary ops: | ^ &
mp_parse_node_t pn = peek_result(parser, num_args - 1);
if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
return false;
}
mp_binary_op_t op;
- if (rule->rule_id == RULE_expr) {
+ if (rule_id == RULE_expr) {
op = MP_BINARY_OP_OR;
- } else if (rule->rule_id == RULE_xor_expr) {
+ } else if (rule_id == RULE_xor_expr) {
op = MP_BINARY_OP_XOR;
} else {
op = MP_BINARY_OP_AND;
@@ -534,9 +633,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
}
arg0 = mp_binary_op(op, arg0, arg1);
}
- } else if (rule->rule_id == RULE_shift_expr
- || rule->rule_id == RULE_arith_expr
- || rule->rule_id == RULE_term) {
+ } else if (rule_id == RULE_shift_expr
+ || rule_id == RULE_arith_expr
+ || rule_id == RULE_term) {
// folding for binary ops: << >> + - * / % //
mp_parse_node_t pn = peek_result(parser, num_args - 1);
if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
@@ -580,7 +679,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
}
arg0 = mp_binary_op(op, arg0, arg1);
}
- } else if (rule->rule_id == RULE_factor_2) {
+ } else if (rule_id == RULE_factor_2) {
// folding for unary ops: + - ~
mp_parse_node_t pn = peek_result(parser, 0);
if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
@@ -599,7 +698,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
arg0 = mp_unary_op(op, arg0);
#if MICROPY_COMP_CONST
- } else if (rule->rule_id == RULE_expr_stmt) {
+ } else if (rule_id == RULE_expr_stmt) {
mp_parse_node_t pn1 = peek_result(parser, 0);
if (!MP_PARSE_NODE_IS_NULL(pn1)
&& !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign)
@@ -638,7 +737,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
if (qstr_str(id)[0] == '_') {
pop_result(parser); // pop const(value)
pop_result(parser); // pop id
- push_result_rule(parser, 0, rules[RULE_pass_stmt], 0); // replace with "pass"
+ push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass"
return true;
}
@@ -654,7 +753,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
#endif
#if MICROPY_COMP_MODULE_CONST
- } else if (rule->rule_id == RULE_atom_expr_normal) {
+ } else if (rule_id == RULE_atom_expr_normal) {
mp_parse_node_t pn0 = peek_result(parser, 1);
mp_parse_node_t pn1 = peek_result(parser, 0);
if (!(MP_PARSE_NODE_IS_ID(pn0)
@@ -689,7 +788,7 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
pop_result(parser);
}
if (MP_OBJ_IS_SMALL_INT(arg0)) {
- push_result_node(parser, mp_parse_node_new_small_int(MP_OBJ_SMALL_INT_VALUE(arg0)));
+ push_result_node(parser, mp_parse_node_new_small_int_checked(parser, arg0));
} else {
// TODO reuse memory for parse node struct?
push_result_node(parser, make_node_const_object(parser, 0, arg0));
@@ -699,9 +798,9 @@ STATIC bool fold_constants(parser_t *parser, const rule_t *rule, size_t num_args
}
#endif
-STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *rule, size_t num_args) {
+STATIC void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
// optimise away parenthesis around an expression if possible
- if (rule->rule_id == RULE_atom_paren) {
+ if (rule_id == RULE_atom_paren) {
// there should be just 1 arg for this rule
mp_parse_node_t pn = peek_result(parser, 0);
if (MP_PARSE_NODE_IS_NULL(pn)) {
@@ -715,11 +814,11 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru
}
#if MICROPY_COMP_CONST_FOLDING
- if (fold_logical_constants(parser, rule, &num_args)) {
+ if (fold_logical_constants(parser, rule_id, &num_args)) {
// we folded this rule so return straight away
return;
}
- if (fold_constants(parser, rule, num_args)) {
+ if (fold_constants(parser, rule_id, num_args)) {
// we folded this rule so return straight away
return;
}
@@ -727,7 +826,7 @@ STATIC void push_result_rule(parser_t *parser, size_t src_line, const rule_t *ru
mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args);
pn->source_line = src_line;
- pn->kind_num_nodes = (rule->rule_id & 0xff) | (num_args << 8);
+ pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);
for (size_t i = num_args; i > 0; i--) {
pn->nodes[i - 1] = pop_result(parser);
}
@@ -783,14 +882,11 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
case MP_PARSE_EVAL_INPUT: top_level_rule = RULE_eval_input; break;
default: top_level_rule = RULE_file_input;
}
- push_rule(&parser, lex->tok_line, rules[top_level_rule], 0);
+ push_rule(&parser, lex->tok_line, top_level_rule, 0);
// parse!
- size_t n, i; // state for the current rule
- size_t rule_src_line; // source line for the first token matched by the current rule
bool backtrack = false;
- const rule_t *rule = NULL;
for (;;) {
next_rule:
@@ -798,19 +894,24 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
break;
}
- pop_rule(&parser, &rule, &i, &rule_src_line);
- n = rule->act & RULE_ACT_ARG_MASK;
+ // Pop the next rule to process it
+ size_t i; // state for the current rule
+ size_t rule_src_line; // source line for the first token matched by the current rule
+ uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line);
+ uint8_t rule_act = rule_act_table[rule_id];
+ const uint16_t *rule_arg = get_rule_arg(rule_id);
+ size_t n = rule_act & RULE_ACT_ARG_MASK;
- /*
+ #if 0
// debugging
- printf("depth=%d ", parser.rule_stack_top);
+ printf("depth=" UINT_FMT " ", parser.rule_stack_top);
for (int j = 0; j < parser.rule_stack_top; ++j) {
printf(" ");
}
- printf("%s n=%d i=%d bt=%d\n", rule->rule_name, n, i, backtrack);
- */
+ printf("%s n=" UINT_FMT " i=" UINT_FMT " bt=%d\n", rule_name_table[rule_id], n, i, backtrack);
+ #endif
- switch (rule->act & RULE_ACT_KIND_MASK) {
+ switch (rule_act & RULE_ACT_KIND_MASK) {
case RULE_ACT_OR:
if (i > 0 && !backtrack) {
goto next_rule;
@@ -818,19 +919,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
backtrack = false;
}
for (; i < n; ++i) {
- uint16_t kind = rule->arg[i] & RULE_ARG_KIND_MASK;
+ uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK;
if (kind == RULE_ARG_TOK) {
- if (lex->tok_kind == (rule->arg[i] & RULE_ARG_ARG_MASK)) {
- push_result_token(&parser, rule);
+ if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) {
+ push_result_token(&parser, rule_id);
mp_lexer_to_next(lex);
goto next_rule;
}
} else {
assert(kind == RULE_ARG_RULE);
if (i + 1 < n) {
- push_rule(&parser, rule_src_line, rule, i + 1); // save this or-rule
+ push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule
}
- push_rule_from_arg(&parser, rule->arg[i]); // push child of or-rule
+ push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule
goto next_rule;
}
}
@@ -842,7 +943,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// failed, backtrack if we can, else syntax error
if (backtrack) {
assert(i > 0);
- if ((rule->arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) {
+ if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) {
// an optional rule that failed, so continue with next arg
push_result_node(&parser, MP_PARSE_NODE_NULL);
backtrack = false;
@@ -859,13 +960,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// progress through the rule
for (; i < n; ++i) {
- if ((rule->arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
+ if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
// need to match a token
- mp_token_kind_t tok_kind = rule->arg[i] & RULE_ARG_ARG_MASK;
+ mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK;
if (lex->tok_kind == tok_kind) {
// matched token
if (tok_kind == MP_TOKEN_NAME) {
- push_result_token(&parser, rule);
+ push_result_token(&parser, rule_id);
}
mp_lexer_to_next(lex);
} else {
@@ -880,8 +981,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
}
} else {
- push_rule(&parser, rule_src_line, rule, i + 1); // save this and-rule
- push_rule_from_arg(&parser, rule->arg[i]); // push child of and-rule
+ push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule
+ push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule
goto next_rule;
}
}
@@ -892,7 +993,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
#if !MICROPY_ENABLE_DOC_STRING
// this code discards lonely statements, such as doc strings
- if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
+ if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
mp_parse_node_t p = peek_result(&parser, 1);
if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p))
|| MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) {
@@ -901,7 +1002,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// Pushing the "pass" rule here will overwrite any RULE_const_object
// entry that was on the result stack, allowing the GC to reclaim
// the memory from the const object when needed.
- push_result_rule(&parser, rule_src_line, rules[RULE_pass_stmt], 0);
+ push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0);
break;
}
}
@@ -912,8 +1013,8 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
size_t num_not_nil = 0;
for (size_t x = n; x > 0;) {
--x;
- if ((rule->arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
- mp_token_kind_t tok_kind = rule->arg[x] & RULE_ARG_ARG_MASK;
+ if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
+ mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK;
if (tok_kind == MP_TOKEN_NAME) {
// only tokens which were names are pushed to stack
i += 1;
@@ -928,7 +1029,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
}
- if (num_not_nil == 1 && (rule->act & RULE_ACT_ALLOW_IDENT)) {
+ if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) {
// this rule has only 1 argument and should not be emitted
mp_parse_node_t pn = MP_PARSE_NODE_NULL;
for (size_t x = 0; x < i; ++x) {
@@ -941,19 +1042,19 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
} else {
// this rule must be emitted
- if (rule->act & RULE_ACT_ADD_BLANK) {
+ if (rule_act & RULE_ACT_ADD_BLANK) {
// and add an extra blank node at the end (used by the compiler to store data)
push_result_node(&parser, MP_PARSE_NODE_NULL);
i += 1;
}
- push_result_rule(&parser, rule_src_line, rule, i);
+ push_result_rule(&parser, rule_src_line, rule_id, i);
}
break;
}
default: {
- assert((rule->act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST);
+ assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST);
// n=2 is: item item*
// n=1 is: item (sep item)*
@@ -991,13 +1092,13 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
} else {
for (;;) {
- size_t arg = rule->arg[i & 1 & n];
+ size_t arg = rule_arg[i & 1 & n];
if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) {
if (i & 1 & n) {
// separators which are tokens are not pushed to result stack
} else {
- push_result_token(&parser, rule);
+ push_result_token(&parser, rule_id);
}
mp_lexer_to_next(lex);
// got element of list, so continue parsing list
@@ -1010,7 +1111,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
}
} else {
assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE);
- push_rule(&parser, rule_src_line, rule, i + 1); // save this list-rule
+ push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule
push_rule_from_arg(&parser, arg); // push child of list-rule
goto next_rule;
}
@@ -1020,7 +1121,7 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// compute number of elements in list, result in i
i -= 1;
- if ((n & 1) && (rule->arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
+ if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
// don't count separators when they are tokens
i = (i + 1) / 2;
}
@@ -1029,12 +1130,12 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
// list matched single item
if (had_trailing_sep) {
// if there was a trailing separator, make a list of a single item
- push_result_rule(&parser, rule_src_line, rule, i);
+ push_result_rule(&parser, rule_src_line, rule_id, i);
} else {
// just leave single item on stack (ie don't wrap in a list)
}
} else {
- push_result_rule(&parser, rule_src_line, rule, i);
+ push_result_rule(&parser, rule_src_line, rule_id, i);
}
break;
}
diff --git a/py/parsenum.c b/py/parsenum.c
index bacf4f442..e3644b171 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -83,6 +83,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m
mp_uint_t dig = *str;
if ('0' <= dig && dig <= '9') {
dig -= '0';
+ } else if (dig == '_') {
+ continue;
} else {
dig |= 0x20; // make digit lower-case
if ('a' <= dig && dig <= 'z') {
@@ -170,6 +172,19 @@ typedef enum {
mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex) {
#if MICROPY_PY_BUILTINS_FLOAT
+
+// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing
+// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+#define DEC_VAL_MAX 1e20F
+#define SMALL_NORMAL_VAL (1e-37F)
+#define SMALL_NORMAL_EXP (-37)
+#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+#define DEC_VAL_MAX 1e200
+#define SMALL_NORMAL_VAL (1e-307)
+#define SMALL_NORMAL_EXP (-307)
+#endif
+
const char *top = str + len;
mp_float_t dec_val = 0;
bool dec_neg = false;
@@ -214,20 +229,32 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
// string should be a decimal number
parse_dec_in_t in = PARSE_DEC_IN_INTG;
bool exp_neg = false;
- mp_float_t frac_mult = 0.1;
- mp_int_t exp_val = 0;
+ int exp_val = 0;
+ int exp_extra = 0;
while (str < top) {
- mp_uint_t dig = *str++;
+ unsigned int dig = *str++;
if ('0' <= dig && dig <= '9') {
dig -= '0';
if (in == PARSE_DEC_IN_EXP) {
- exp_val = 10 * exp_val + dig;
+ // don't overflow exp_val when adding next digit, instead just truncate
+ // it and the resulting float will still be correct, either inf or 0.0
+ // (use INT_MAX/2 to allow adding exp_extra at the end without overflow)
+ if (exp_val < (INT_MAX / 2 - 9) / 10) {
+ exp_val = 10 * exp_val + dig;
+ }
} else {
- if (in == PARSE_DEC_IN_FRAC) {
- dec_val += dig * frac_mult;
- frac_mult *= MICROPY_FLOAT_CONST(0.1);
- } else {
+ if (dec_val < DEC_VAL_MAX) {
+ // dec_val won't overflow so keep accumulating
dec_val = 10 * dec_val + dig;
+ if (in == PARSE_DEC_IN_FRAC) {
+ --exp_extra;
+ }
+ } else {
+ // dec_val might overflow and we anyway can't represent more digits
+ // of precision, so ignore the digit and just adjust the exponent
+ if (in == PARSE_DEC_IN_INTG) {
+ ++exp_extra;
+ }
}
}
} else if (in == PARSE_DEC_IN_INTG && dig == '.') {
@@ -248,6 +275,8 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
} else if (allow_imag && (dig | 0x20) == 'j') {
imag = true;
break;
+ } else if (dig == '_') {
+ continue;
} else {
// unknown character
str--;
@@ -260,7 +289,12 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
exp_val = -exp_val;
}
- // apply the exponent
+ // apply the exponent, making sure it's not a subnormal value
+ exp_val += exp_extra;
+ if (exp_val < SMALL_NORMAL_EXP) {
+ exp_val -= SMALL_NORMAL_EXP;
+ dec_val *= SMALL_NORMAL_VAL;
+ }
dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val);
}
@@ -289,11 +323,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
return mp_obj_new_complex(0, dec_val);
} else if (force_complex) {
return mp_obj_new_complex(dec_val, 0);
+ }
#else
if (imag || force_complex) {
raise_exc(mp_obj_new_exception_msg(&mp_type_ValueError, "complex values not supported"), lex);
+ }
#endif
- } else {
+ else {
return mp_obj_new_float(dec_val);
}
diff --git a/py/persistentcode.c b/py/persistentcode.c
index ba126a3fb..290797a7c 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -199,7 +199,11 @@ STATIC mp_raw_code_t *load_raw_code(mp_reader_t *reader) {
// create raw_code and return it
mp_raw_code_t *rc = mp_emit_glue_new_raw_code();
- mp_emit_glue_assign_bytecode(rc, bytecode, bc_len, const_table,
+ mp_emit_glue_assign_bytecode(rc, bytecode,
+ #if MICROPY_PERSISTENT_CODE_SAVE || MICROPY_DEBUG_PRINTERS
+ bc_len,
+ #endif
+ const_table,
#if MICROPY_PERSISTENT_CODE_SAVE
n_obj, n_raw_code,
#endif
diff --git a/py/py.mk b/py/py.mk
index e934c3a83..cad8b53ec 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -13,6 +13,9 @@ ifneq ($(QSTR_AUTOGEN_DISABLE),1)
QSTR_DEFS_COLLECTED = $(HEADER_BUILD)/qstrdefs.collected.h
endif
+# Any files listed by this variable will cause a full regeneration of qstrs
+QSTR_GLOBAL_DEPENDENCIES += $(PY_SRC)/mpconfig.h mpconfigport.h
+
# some code is performance bottleneck and compiled with other optimization options
CSUPEROPT = -O3
@@ -101,8 +104,9 @@ $(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS)
endif
# py object files
-PY_O_BASENAME = \
+PY_CORE_O_BASENAME = $(addprefix py/,\
mpstate.o \
+ nlr.o \
nlrx86.o \
nlrx64.o \
nlrthumb.o \
@@ -111,6 +115,7 @@ PY_O_BASENAME = \
malloc.o \
gc.o \
gc_long_lived.o \
+ pystack.o \
qstr.o \
vstr.o \
mpprint.o \
@@ -157,6 +162,7 @@ PY_O_BASENAME = \
objcell.o \
objclosure.o \
objcomplex.o \
+ objdeque.o \
objdict.o \
objenumerate.o \
objexcept.o \
@@ -213,41 +219,49 @@ PY_O_BASENAME = \
repl.o \
smallint.o \
frozenmod.o \
- ../extmod/moductypes.o \
- ../extmod/modujson.o \
- ../extmod/modure.o \
- ../extmod/moduzlib.o \
- ../extmod/moduheapq.o \
- ../extmod/modutimeq.o \
- ../extmod/moduhashlib.o \
- ../extmod/modubinascii.o \
- ../extmod/virtpin.o \
- ../extmod/machine_mem.o \
- ../extmod/machine_pinbase.o \
- ../extmod/machine_signal.o \
- ../extmod/machine_pulse.o \
- ../extmod/machine_i2c.o \
- ../extmod/machine_spi.o \
- ../extmod/modussl_axtls.o \
- ../extmod/modussl_mbedtls.o \
- ../extmod/modurandom.o \
- ../extmod/moduselect.o \
- ../extmod/modwebsocket.o \
- ../extmod/modwebrepl.o \
- ../extmod/modframebuf.o \
- ../extmod/vfs.o \
- ../extmod/vfs_reader.o \
- ../extmod/vfs_fat.o \
- ../extmod/vfs_fat_diskio.o \
- ../extmod/vfs_fat_file.o \
- ../extmod/vfs_fat_misc.o \
- ../extmod/utime_mphal.o \
- ../extmod/uos_dupterm.o \
- ../lib/embed/abort_.o \
- ../lib/utils/printf.o \
+ )
+
+PY_EXTMOD_O_BASENAME = \
+ extmod/moductypes.o \
+ extmod/modujson.o \
+ extmod/modure.o \
+ extmod/moduzlib.o \
+ extmod/moduheapq.o \
+ extmod/modutimeq.o \
+ extmod/moduhashlib.o \
+ extmod/modubinascii.o \
+ extmod/virtpin.o \
+ extmod/machine_mem.o \
+ extmod/machine_pinbase.o \
+ extmod/machine_signal.o \
+ extmod/machine_pulse.o \
+ extmod/machine_i2c.o \
+ extmod/machine_spi.o \
+ extmod/modussl_axtls.o \
+ extmod/modussl_mbedtls.o \
+ extmod/modurandom.o \
+ extmod/moduselect.o \
+ extmod/modwebsocket.o \
+ extmod/modwebrepl.o \
+ extmod/modframebuf.o \
+ extmod/vfs.o \
+ extmod/vfs_reader.o \
+ extmod/vfs_posix.o \
+ extmod/vfs_posix_file.o \
+ extmod/vfs_fat.o \
+ extmod/vfs_fat_diskio.o \
+ extmod/vfs_fat_file.o \
+ extmod/utime_mphal.o \
+ extmod/uos_dupterm.o \
+ lib/embed/abort_.o \
+ lib/utils/printf.o \
# prepend the build destination prefix to the py object files
-PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME))
+PY_CORE_O = $(addprefix $(BUILD)/, $(PY_CORE_O_BASENAME))
+PY_EXTMOD_O = $(addprefix $(BUILD)/, $(PY_EXTMOD_O_BASENAME))
+
+# this is a convenience variable for ports that want core, extmod and frozen code
+PY_O = $(PY_CORE_O) $(PY_EXTMOD_O)
# object file for frozen files
ifneq ($(FROZEN_DIR),)
@@ -263,8 +277,8 @@ PY_O += $(BUILD)/frozen_mpy.o
endif
# Sources that may contain qstrings
-SRC_QSTR_IGNORE = nlr% emitnx86% emitnx64% emitnthumb% emitnarm% emitnxtensa%
-SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c)
+SRC_QSTR_IGNORE = py/nlr%
+SRC_QSTR = $(SRC_MOD) $(filter-out $(SRC_QSTR_IGNORE),$(PY_CORE_O_BASENAME:.o=.c)) $(PY_EXTMOD_O_BASENAME:.o=.c)
# Anything that depends on FORCE will be considered out-of-date
FORCE:
@@ -291,28 +305,6 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(PY_QSTR_DEFS) $(QSTR_DEFS) $(QSTR_DEFS_C
# that the function preludes are of a minimal and predictable form.
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
-# emitters
-
-$(PY_BUILD)/emitnx64.o: CFLAGS += -DN_X64
-$(PY_BUILD)/emitnx64.o: py/emitnative.c
- $(call compile_c)
-
-$(PY_BUILD)/emitnx86.o: CFLAGS += -DN_X86
-$(PY_BUILD)/emitnx86.o: py/emitnative.c
- $(call compile_c)
-
-$(PY_BUILD)/emitnthumb.o: CFLAGS += -DN_THUMB
-$(PY_BUILD)/emitnthumb.o: py/emitnative.c
- $(call compile_c)
-
-$(PY_BUILD)/emitnarm.o: CFLAGS += -DN_ARM
-$(PY_BUILD)/emitnarm.o: py/emitnative.c
- $(call compile_c)
-
-$(PY_BUILD)/emitnxtensa.o: CFLAGS += -DN_XTENSA
-$(PY_BUILD)/emitnxtensa.o: py/emitnative.c
- $(call compile_c)
-
# optimising gc for speed; 5ms down to 4ms on pybv2
$(PY_BUILD)/gc.o: CFLAGS += $(CSUPEROPT)
diff --git a/py/pystack.c b/py/pystack.c
new file mode 100644
index 000000000..552e59d53
--- /dev/null
+++ b/py/pystack.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "py/runtime.h"
+
+#if MICROPY_ENABLE_PYSTACK
+
+void mp_pystack_init(void *start, void *end) {
+ MP_STATE_THREAD(pystack_start) = start;
+ MP_STATE_THREAD(pystack_end) = end;
+ MP_STATE_THREAD(pystack_cur) = start;
+}
+
+void *mp_pystack_alloc(size_t n_bytes) {
+ n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1);
+ #if MP_PYSTACK_DEBUG
+ n_bytes += MICROPY_PYSTACK_ALIGN;
+ #endif
+ if (MP_STATE_THREAD(pystack_cur) + n_bytes > MP_STATE_THREAD(pystack_end)) {
+ // out of memory in the pystack
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
+ MP_OBJ_NEW_QSTR(MP_QSTR_pystack_space_exhausted)));
+ }
+ void *ptr = MP_STATE_THREAD(pystack_cur);
+ MP_STATE_THREAD(pystack_cur) += n_bytes;
+ #if MP_PYSTACK_DEBUG
+ *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN) = n_bytes;
+ #endif
+ return ptr;
+}
+
+#endif
diff --git a/py/pystack.h b/py/pystack.h
new file mode 100644
index 000000000..82ac3743d
--- /dev/null
+++ b/py/pystack.h
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_PY_PYSTACK_H
+#define MICROPY_INCLUDED_PY_PYSTACK_H
+
+#include "py/mpstate.h"
+
+// Enable this debugging option to check that the amount of memory freed is
+// consistent with amounts that were previously allocated.
+#define MP_PYSTACK_DEBUG (0)
+
+#if MICROPY_ENABLE_PYSTACK
+
+void mp_pystack_init(void *start, void *end);
+void *mp_pystack_alloc(size_t n_bytes);
+
+// This function can free multiple continuous blocks at once: just pass the
+// pointer to the block that was allocated first and it and all subsequently
+// allocated blocks will be freed.
+static inline void mp_pystack_free(void *ptr) {
+ assert((uint8_t*)ptr >= MP_STATE_THREAD(pystack_start));
+ assert((uint8_t*)ptr <= MP_STATE_THREAD(pystack_cur));
+ #if MP_PYSTACK_DEBUG
+ size_t n_bytes_to_free = MP_STATE_THREAD(pystack_cur) - (uint8_t*)ptr;
+ size_t n_bytes = *(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN);
+ while (n_bytes < n_bytes_to_free) {
+ n_bytes += *(size_t*)(MP_STATE_THREAD(pystack_cur) - n_bytes - MICROPY_PYSTACK_ALIGN);
+ }
+ if (n_bytes != n_bytes_to_free) {
+ mp_printf(&mp_plat_print, "mp_pystack_free() failed: %u != %u\n", (uint)n_bytes_to_free,
+ (uint)*(size_t*)(MP_STATE_THREAD(pystack_cur) - MICROPY_PYSTACK_ALIGN));
+ assert(0);
+ }
+ #endif
+ MP_STATE_THREAD(pystack_cur) = (uint8_t*)ptr;
+}
+
+static inline void mp_pystack_realloc(void *ptr, size_t n_bytes) {
+ mp_pystack_free(ptr);
+ mp_pystack_alloc(n_bytes);
+}
+
+static inline size_t mp_pystack_usage(void) {
+ return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start);
+}
+
+static inline size_t mp_pystack_limit(void) {
+ return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start);
+}
+
+#endif
+
+#if !MICROPY_ENABLE_PYSTACK
+
+#define mp_local_alloc(n_bytes) alloca(n_bytes)
+
+static inline void mp_local_free(void *ptr) {
+ (void)ptr;
+}
+
+static inline void *mp_nonlocal_alloc(size_t n_bytes) {
+ return m_new(uint8_t, n_bytes);
+}
+
+static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
+ return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes);
+}
+
+static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {
+ m_del(uint8_t, ptr, n_bytes);
+}
+
+#else
+
+static inline void *mp_local_alloc(size_t n_bytes) {
+ return mp_pystack_alloc(n_bytes);
+}
+
+static inline void mp_local_free(void *ptr) {
+ mp_pystack_free(ptr);
+}
+
+static inline void *mp_nonlocal_alloc(size_t n_bytes) {
+ return mp_pystack_alloc(n_bytes);
+}
+
+static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
+ (void)old_n_bytes;
+ mp_pystack_realloc(ptr, new_n_bytes);
+ return ptr;
+}
+
+static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {
+ (void)n_bytes;
+ mp_pystack_free(ptr);
+}
+
+#endif
+
+#endif // MICROPY_INCLUDED_PY_PYSTACK_H
diff --git a/py/qstr.c b/py/qstr.c
index de4dc6240..c68f3dfec 100755
--- a/py/qstr.c
+++ b/py/qstr.c
@@ -128,14 +128,12 @@ void qstr_init(void) {
STATIC const byte *find_qstr(qstr q) {
// search pool for this qstr
- for (qstr_pool_t *pool = MP_STATE_VM(last_pool); pool != NULL; pool = pool->prev) {
- if (q >= pool->total_prev_len) {
- return pool->qstrs[q - pool->total_prev_len];
- }
+ // total_prev_len==0 in the final pool, so the loop will always terminate
+ qstr_pool_t *pool = MP_STATE_VM(last_pool);
+ while (q < pool->total_prev_len) {
+ pool = pool->prev;
}
-
- // not found
- return 0;
+ return pool->qstrs[q - pool->total_prev_len];
}
// qstr_mutex must be taken while in this function
@@ -248,29 +246,6 @@ qstr qstr_from_strn(const char *str, size_t len) {
return q;
}
-byte *qstr_build_start(size_t len, byte **q_ptr) {
- assert(len < (1 << (8 * MICROPY_QSTR_BYTES_IN_LEN)));
- *q_ptr = m_new(byte, MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len + 1);
- Q_SET_LENGTH(*q_ptr, len);
- return Q_GET_DATA(*q_ptr);
-}
-
-qstr qstr_build_end(byte *q_ptr) {
- QSTR_ENTER();
- qstr q = qstr_find_strn((const char*)Q_GET_DATA(q_ptr), Q_GET_LENGTH(q_ptr));
- if (q == 0) {
- size_t len = Q_GET_LENGTH(q_ptr);
- mp_uint_t hash = qstr_compute_hash(Q_GET_DATA(q_ptr), len);
- Q_SET_HASH(q_ptr, hash);
- q_ptr[MICROPY_QSTR_BYTES_IN_HASH + MICROPY_QSTR_BYTES_IN_LEN + len] = '\0';
- q = qstr_add(gc_make_long_lived(q_ptr));
- } else {
- m_del(byte, q_ptr, Q_GET_ALLOC(q_ptr));
- }
- QSTR_EXIT();
- return q;
-}
-
mp_uint_t qstr_hash(qstr q) {
return Q_GET_HASH(find_qstr(q));
}
diff --git a/py/qstr.h b/py/qstr.h
index e2bdcc351..f4375ee0e 100644
--- a/py/qstr.h
+++ b/py/qstr.h
@@ -56,6 +56,7 @@ typedef struct _qstr_pool_t {
} qstr_pool_t;
#define QSTR_FROM_STR_STATIC(s) (qstr_from_strn((s), strlen(s)))
+#define QSTR_TOTAL() (MP_STATE_VM(last_pool)->total_prev_len + MP_STATE_VM(last_pool)->len)
void qstr_init(void);
@@ -65,9 +66,6 @@ qstr qstr_find_strn(const char *str, size_t str_len); // returns MP_QSTR_NULL if
qstr qstr_from_str(const char *str);
qstr qstr_from_strn(const char *str, size_t len);
-byte *qstr_build_start(size_t len, byte **q_ptr);
-qstr qstr_build_end(byte *q_ptr);
-
mp_uint_t qstr_hash(qstr q);
const char *qstr_str(qstr q);
size_t qstr_len(qstr q);
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index 4ded5be08..a60905812 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -40,6 +40,7 @@ Q(/)
Q(%#o)
Q(%#x)
Q({:#b})
+Q( )
Q(\n)
Q(maximum recursion depth exceeded)
Q(<module>)
@@ -51,3 +52,7 @@ Q(<genexpr>)
Q(<string>)
Q(<stdin>)
Q(utf-8)
+
+#if MICROPY_ENABLE_PYSTACK
+Q(pystack exhausted)
+#endif
diff --git a/py/reader.c b/py/reader.c
index c4d18d53d..80364104b 100644
--- a/py/reader.c
+++ b/py/reader.c
@@ -124,6 +124,8 @@ void mp_reader_new_file_from_fd(mp_reader_t *reader, int fd, bool close_fd) {
reader->close = mp_reader_posix_close;
}
+#if !MICROPY_VFS_POSIX
+// If MICROPY_VFS_POSIX is defined then this function is provided by the VFS layer
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
int fd = open(filename, O_RDONLY, 0644);
if (fd < 0) {
@@ -131,5 +133,6 @@ void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
}
mp_reader_new_file_from_fd(reader, fd, true);
}
+#endif
#endif
diff --git a/py/repl.c b/py/repl.c
index 7e8922e19..da0fefb3a 100644
--- a/py/repl.c
+++ b/py/repl.c
@@ -27,6 +27,7 @@
#include <string.h>
#include "py/obj.h"
#include "py/runtime.h"
+#include "py/builtin.h"
#include "py/repl.h"
#if MICROPY_HELPER_REPL
@@ -105,8 +106,13 @@ bool mp_repl_continue_with_input(const char *input) {
}
}
- // continue if unmatched brackets or quotes
- if (n_paren > 0 || n_brack > 0 || n_brace > 0 || in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) {
+ // continue if unmatched 3-quotes
+ if (in_quote == Q_3_SINGLE || in_quote == Q_3_DOUBLE) {
+ return true;
+ }
+
+ // continue if unmatched brackets, but only if not in a 1-quote
+ if ((n_paren > 0 || n_brack > 0 || n_brace > 0) && in_quote == Q_NONE) {
return true;
}
@@ -136,8 +142,11 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
}
}
- // begin search in locals dict
- mp_obj_dict_t *dict = mp_locals_get();
+ size_t nqstr = QSTR_TOTAL();
+
+ // begin search in outer global dict which is accessed from __main__
+ mp_obj_t obj = MP_OBJ_FROM_PTR(&mp_module___main__);
+ mp_obj_t dest[2];
for (;;) {
// get next word in string to complete
@@ -148,43 +157,20 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
size_t s_len = str - s_start;
if (str < top) {
- // a complete word, lookup in current dict
-
- mp_obj_t obj = MP_OBJ_NULL;
- for (size_t i = 0; i < dict->map.alloc; i++) {
- if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
- size_t d_len;
- const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
- if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) {
- obj = dict->map.table[i].value;
- break;
- }
- }
+ // a complete word, lookup in current object
+ qstr q = qstr_find_strn(s_start, s_len);
+ if (q == MP_QSTR_NULL) {
+ // lookup will fail
+ return 0;
}
+ mp_load_method_protected(obj, q, dest, true);
+ obj = dest[0]; // attribute, method, or MP_OBJ_NULL if nothing found
if (obj == MP_OBJ_NULL) {
// lookup failed
return 0;
}
- // found an object of this name; try to get its dict
- if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) {
- dict = mp_obj_module_get_globals(obj);
- } else {
- mp_obj_type_t *type;
- if (MP_OBJ_IS_TYPE(obj, &mp_type_type)) {
- type = MP_OBJ_TO_PTR(obj);
- } else {
- type = mp_obj_get_type(obj);
- }
- if (type->locals_dict != NULL && type->locals_dict->base.type == &mp_type_dict) {
- dict = type->locals_dict;
- } else {
- // obj has no dict
- return 0;
- }
- }
-
// skip '.' to move to next word
++str;
@@ -192,14 +178,15 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
// end of string, do completion on this partial name
// look for matches
- int n_found = 0;
const char *match_str = NULL;
size_t match_len = 0;
- for (size_t i = 0; i < dict->map.alloc; i++) {
- if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
- size_t d_len;
- const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
- if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
+ qstr q_first = 0, q_last = 0;
+ for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
+ size_t d_len;
+ const char *d_str = (const char*)qstr_data(q, &d_len);
+ if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
+ mp_load_method_protected(obj, q, dest, true);
+ if (dest[0] != MP_OBJ_NULL) {
if (match_str == NULL) {
match_str = d_str;
match_len = d_len;
@@ -213,13 +200,16 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
}
}
}
- ++n_found;
+ if (q_first == 0) {
+ q_first = q;
+ }
+ q_last = q;
}
}
}
// nothing found
- if (n_found == 0) {
+ if (q_first == 0) {
// If there're no better alternatives, and if it's first word
// in the line, try to complete "import".
if (s_start == org_str) {
@@ -234,7 +224,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
}
// 1 match found, or multiple matches with a common prefix
- if (n_found == 1 || match_len > s_len) {
+ if (q_first == q_last || match_len > s_len) {
*compl_str = match_str + s_len;
return match_len - s_len;
}
@@ -245,11 +235,12 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
#define MAX_LINE_LEN (4 * WORD_SLOT_LEN)
int line_len = MAX_LINE_LEN; // force a newline for first word
- for (size_t i = 0; i < dict->map.alloc; i++) {
- if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) {
- size_t d_len;
- const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len);
- if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
+ for (qstr q = q_first; q <= q_last; ++q) {
+ size_t d_len;
+ const char *d_str = (const char*)qstr_data(q, &d_len);
+ if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
+ mp_load_method_protected(obj, q, dest, true);
+ if (dest[0] != MP_OBJ_NULL) {
int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len;
if (gap < 2) {
gap += WORD_SLOT_LEN;
diff --git a/py/runtime.c b/py/runtime.c
index a7ff57a47..a9c0ef1e2 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -95,8 +95,10 @@ void mp_init(void) {
MICROPY_PORT_INIT_FUNC;
#endif
+ #if MICROPY_ENABLE_COMPILER
// optimization disabled by default
MP_STATE_VM(mp_optimise_value) = 0;
+ #endif
// init global module dict
mp_obj_dict_init(&MP_STATE_VM(mp_loaded_modules_dict), 3);
@@ -118,7 +120,6 @@ void mp_init(void) {
for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) {
MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL;
}
- MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL;
#endif
#ifdef MICROPY_FSUSERMOUNT
@@ -246,7 +247,7 @@ void mp_delete_global(qstr qst) {
}
mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
- DEBUG_OP_printf("unary " UINT_FMT " %p\n", op, arg);
+ DEBUG_OP_printf("unary " UINT_FMT " %q %p\n", op, mp_unary_op_method_name[op], arg);
if (op == MP_UNARY_OP_NOT) {
// "not x" is the negative of whether "x" is true per Python semantics
@@ -307,7 +308,7 @@ mp_obj_t mp_unary_op(mp_unary_op_t op, mp_obj_t arg) {
}
mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
- DEBUG_OP_printf("binary " UINT_FMT " %p %p\n", op, lhs, rhs);
+ DEBUG_OP_printf("binary " UINT_FMT " %q %p %p\n", op, mp_binary_op_method_name[op], lhs, rhs);
// TODO correctly distinguish inplace operators for mutable objects
// lookup logic that CPython uses for +=:
@@ -445,7 +446,6 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
// use standard precision
return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
}
- break;
}
case MP_BINARY_OP_FLOOR_DIVIDE:
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
@@ -520,10 +520,10 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
return MP_OBJ_FROM_PTR(tuple);
}
- case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val); break;
- case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val); break;
- case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val); break;
- case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val); break;
+ case MP_BINARY_OP_LESS: return mp_obj_new_bool(lhs_val < rhs_val);
+ case MP_BINARY_OP_MORE: return mp_obj_new_bool(lhs_val > rhs_val);
+ case MP_BINARY_OP_LESS_EQUAL: return mp_obj_new_bool(lhs_val <= rhs_val);
+ case MP_BINARY_OP_MORE_EQUAL: return mp_obj_new_bool(lhs_val >= rhs_val);
default:
goto unsupported_op;
@@ -555,38 +555,12 @@ mp_obj_t mp_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
}
}
- /* deal with `in`
- *
- * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch
- * needs to go below with swapped arguments
- */
+ // Convert MP_BINARY_OP_IN to MP_BINARY_OP_CONTAINS with swapped args.
if (op == MP_BINARY_OP_IN) {
- mp_obj_type_t *type = mp_obj_get_type(rhs);
- if (type->binary_op != NULL) {
- mp_obj_t res = type->binary_op(op, rhs, lhs);
- if (res != MP_OBJ_NULL) {
- return res;
- }
- }
- if (type->getiter != NULL) {
- /* second attempt, walk the iterator */
- mp_obj_iter_buf_t iter_buf;
- mp_obj_t iter = mp_getiter(rhs, &iter_buf);
- mp_obj_t next;
- while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
- if (mp_obj_equal(next, lhs)) {
- return mp_const_true;
- }
- }
- return mp_const_false;
- }
-
- if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
- mp_raise_TypeError("object not iterable");
- } else {
- mp_raise_TypeError_varg(
- "'%s' object is not iterable", mp_obj_get_type_str(rhs));
- }
+ op = MP_BINARY_OP_CONTAINS;
+ mp_obj_t temp = lhs;
+ lhs = rhs;
+ rhs = temp;
}
// generic binary_op supplied by type
@@ -615,6 +589,20 @@ generic_binary_op:
}
#endif
+ if (op == MP_BINARY_OP_CONTAINS) {
+ // If type didn't support containment then explicitly walk the iterator.
+ // mp_getiter will raise the appropriate exception if lhs is not iterable.
+ mp_obj_iter_buf_t iter_buf;
+ mp_obj_t iter = mp_getiter(lhs, &iter_buf);
+ mp_obj_t next;
+ while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
+ if (mp_obj_equal(next, rhs)) {
+ return mp_const_true;
+ }
+ }
+ return mp_const_false;
+ }
+
unsupported_op:
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_TypeError("unsupported type for operator");
@@ -712,7 +700,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
// allocate memory for the new array of args
args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len);
- args2 = m_new(mp_obj_t, args2_alloc);
+ args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));
// copy the self
if (self != MP_OBJ_NULL) {
@@ -733,7 +721,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
// allocate memory for the new array of args
args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len);
- args2 = m_new(mp_obj_t, args2_alloc);
+ args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));
// copy the self
if (self != MP_OBJ_NULL) {
@@ -749,7 +737,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
// allocate memory for the new array of args
args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3;
- args2 = m_new(mp_obj_t, args2_alloc);
+ args2 = mp_nonlocal_alloc(args2_alloc * sizeof(mp_obj_t));
// copy the self
if (self != MP_OBJ_NULL) {
@@ -766,7 +754,7 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
mp_obj_t item;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (args2_len >= args2_alloc) {
- args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2);
+ args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), args2_alloc * 2 * sizeof(mp_obj_t));
args2_alloc *= 2;
}
args2[args2_len++] = item;
@@ -792,8 +780,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
// the key must be a qstr, so intern it if it's a string
mp_obj_t key = map->table[i].key;
- if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
- key = mp_obj_str_intern(key);
+ if (!MP_OBJ_IS_QSTR(key)) {
+ key = mp_obj_str_intern_checked(key);
}
args2[args2_len++] = key;
args2[args2_len++] = map->table[i].value;
@@ -817,13 +805,13 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
if (new_alloc < 4) {
new_alloc = 4;
}
- args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc);
+ args2 = mp_nonlocal_realloc(args2, args2_alloc * sizeof(mp_obj_t), new_alloc * sizeof(mp_obj_t));
args2_alloc = new_alloc;
}
// the key must be a qstr, so intern it if it's a string
- if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
- key = mp_obj_str_intern(key);
+ if (!MP_OBJ_IS_QSTR(key)) {
+ key = mp_obj_str_intern_checked(key);
}
// get the value corresponding to the key
@@ -849,7 +837,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob
mp_call_prepare_args_n_kw_var(have_self, n_args_n_kw, args, &out_args);
mp_obj_t res = mp_call_function_n_kw(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args);
- m_del(mp_obj_t, out_args.args, out_args.n_alloc);
+ mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));
return res;
}
@@ -1144,6 +1132,22 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
}
}
+// Acts like mp_load_method_maybe but catches AttributeError, and all other exceptions if requested
+void mp_load_method_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_load_method_maybe(obj, attr, dest);
+ nlr_pop();
+ } else {
+ if (!catch_all_exc
+ && !mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t*)nlr.ret_val)->type),
+ MP_OBJ_FROM_PTR(&mp_type_AttributeError))) {
+ // Re-raise the exception
+ nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+ }
+}
+
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
mp_obj_type_t *type = mp_obj_get_type(base);
@@ -1304,13 +1308,12 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
if (type->iternext != NULL && send_value == mp_const_none) {
mp_obj_t ret = type->iternext(self_in);
+ *ret_val = ret;
if (ret != MP_OBJ_STOP_ITERATION) {
- *ret_val = ret;
return MP_VM_RETURN_YIELD;
} else {
// Emulate raise StopIteration()
// Special case, handled in vm.c
- *ret_val = MP_OBJ_NULL;
return MP_VM_RETURN_NORMAL;
}
}
@@ -1372,7 +1375,7 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
// will be propagated up. This behavior is approved by test_pep380.py
// test_delegation_of_close_to_non_generator(),
// test_delegating_throw_to_non_generator()
- *ret_val = throw_value;
+ *ret_val = mp_make_raise_obj(throw_value);
return MP_VM_RETURN_EXCEPTION;
}
}
@@ -1426,6 +1429,8 @@ import_error:
return dest[0];
}
+ #if MICROPY_ENABLE_EXTERNAL_IMPORT
+
// See if it's a package, then can try FS import
if (!mp_obj_is_package(module)) {
goto import_error;
@@ -1436,11 +1441,12 @@ import_error:
const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len);
const uint dot_name_len = pkg_name_len + 1 + qstr_len(name);
- char *dot_name = alloca(dot_name_len);
+ char *dot_name = mp_local_alloc(dot_name_len);
memcpy(dot_name, pkg_name, pkg_name_len);
dot_name[pkg_name_len] = '.';
memcpy(dot_name + pkg_name_len + 1, qstr_str(name), qstr_len(name));
qstr dot_name_q = qstr_from_strn(dot_name, dot_name_len);
+ mp_local_free(dot_name);
mp_obj_t args[5];
args[0] = MP_OBJ_NEW_QSTR(dot_name_q);
@@ -1451,6 +1457,13 @@ import_error:
// TODO lookup __import__ and call that instead of going straight to builtin implementation
return mp_builtin___import__(5, args);
+
+ #else
+
+ // Package import not supported with external imports disabled
+ goto import_error;
+
+ #endif
}
void mp_import_all(mp_obj_t module) {
@@ -1585,3 +1598,10 @@ NORETURN void mp_raise_OSError(int errno_) {
NORETURN void mp_raise_NotImplementedError(const char *msg) {
mp_raise_msg(&mp_type_NotImplementedError, msg);
}
+
+#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
+NORETURN void mp_raise_recursion_depth(void) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
+ MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));
+}
+#endif
diff --git a/py/runtime.h b/py/runtime.h
index a8b6312ff..9e860df15 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -27,6 +27,7 @@
#define MICROPY_INCLUDED_PY_RUNTIME_H
#include "py/mpstate.h"
+#include "py/pystack.h"
typedef enum {
MP_VM_RETURN_NORMAL,
@@ -106,8 +107,9 @@ mp_obj_t mp_call_method_n_kw(size_t n_args, size_t n_kw, const mp_obj_t *args);
mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_obj_t *args);
mp_obj_t mp_call_method_self_n_kw(mp_obj_t meth, mp_obj_t self, size_t n_args, size_t n_kw, const mp_obj_t *args);
// Call function and catch/dump exception - for Python callbacks from C code
-void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg);
-void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
+// (return MP_OBJ_NULL in case of exception).
+mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg);
+mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);
typedef struct _mp_call_args_t {
mp_obj_t fun;
@@ -130,6 +132,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_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_protected(mp_obj_t obj, qstr attr, mp_obj_t *dest, bool catch_all_exc);
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);
@@ -155,8 +158,7 @@ NORETURN void mp_raise_RuntimeError(const char *msg);
NORETURN void mp_raise_ImportError(const char *msg);
NORETURN void mp_raise_IndexError(const char *msg);
NORETURN void mp_raise_OSError(int errno_);
-NORETURN void mp_raise_NotImplementedError(const char *msg);
-NORETURN void mp_exc_recursion_depth(void);
+NORETURN void mp_raise_recursion_depth(void);
#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG
#undef mp_check_self
diff --git a/py/runtime0.h b/py/runtime0.h
index 4709430fb..16434b315 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -133,6 +133,10 @@ typedef enum {
#endif
,
+ // The runtime will convert MP_BINARY_OP_IN to this operator with swapped args.
+ // A type should implement this containment operator instead of MP_BINARY_OP_IN.
+ MP_BINARY_OP_CONTAINS,
+
MP_BINARY_OP_NUM_RUNTIME,
// These 2 are not supported by the runtime and must be synthesised by the emitter
@@ -162,8 +166,8 @@ typedef enum {
MP_F_BUILD_MAP,
MP_F_STORE_MAP,
#if MICROPY_PY_BUILTINS_SET
- MP_F_BUILD_SET,
MP_F_STORE_SET,
+ MP_F_BUILD_SET,
#endif
MP_F_MAKE_FUNCTION_FROM_RAW_CODE,
MP_F_NATIVE_CALL_FUNCTION_N_KW,
diff --git a/py/runtime_utils.c b/py/runtime_utils.c
index bcf3cbf7b..fd3f07111 100644
--- a/py/runtime_utils.c
+++ b/py/runtime_utils.c
@@ -28,22 +28,26 @@
#include "py/mpconfig.h"
#include "py/runtime.h"
-MP_NOINLINE void mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) {
+MP_NOINLINE mp_obj_t mp_call_function_1_protected(mp_obj_t fun, mp_obj_t arg) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
- mp_call_function_1(fun, arg);
+ mp_obj_t ret = mp_call_function_1(fun, arg);
nlr_pop();
+ return ret;
} else {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ return MP_OBJ_NULL;
}
}
-void mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
+mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
- mp_call_function_2(fun, arg1, arg2);
+ mp_obj_t ret = mp_call_function_2(fun, arg1, arg2);
nlr_pop();
+ return ret;
} else {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ return MP_OBJ_NULL;
}
}
diff --git a/py/smallint.h b/py/smallint.h
index 42679a78f..6a3c75236 100644
--- a/py/smallint.h
+++ b/py/smallint.h
@@ -50,10 +50,10 @@
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
-#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffffffff80000000) >> 1))
-#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffffffff80000000) == 0)
+#define MP_SMALL_INT_MIN ((mp_int_t)(((mp_int_t)0xffff800000000000) >> 1))
+#define MP_SMALL_INT_FITS(n) ((((n) ^ ((n) << 1)) & 0xffff800000000000) == 0)
// Mask to truncate mp_int_t to positive value
-#define MP_SMALL_INT_POSITIVE_MASK ~(0xffffffff80000000 | (0xffffffff80000000 >> 1))
+#define MP_SMALL_INT_POSITIVE_MASK ~(0xffff800000000000 | (0xffff800000000000 >> 1))
#endif
diff --git a/py/stackctrl.c b/py/stackctrl.c
index b4ec15b0d..46cbefc8c 100644
--- a/py/stackctrl.c
+++ b/py/stackctrl.c
@@ -52,13 +52,9 @@ void mp_stack_set_limit(mp_uint_t limit) {
MP_STATE_THREAD(stack_limit) = limit;
}
-void mp_exc_recursion_depth(void) {
- mp_raise_RuntimeError("maximum recursion depth exceeded");
-}
-
void mp_stack_check(void) {
if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) {
- mp_exc_recursion_depth();
+ mp_raise_recursion_depth();
}
}
diff --git a/py/stream.c b/py/stream.c
index 453dee769..448de41bb 100644
--- a/py/stream.c
+++ b/py/stream.c
@@ -32,13 +32,6 @@
#include "py/stream.h"
#include "py/runtime.h"
-#if MICROPY_STREAMS_NON_BLOCK
-#include <errno.h>
-#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
-#define EWOULDBLOCK 140
-#endif
-#endif
-
// This file defines generic Python stream read/write methods which
// dispatch to the underlying stream interface of an object.
@@ -54,10 +47,9 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in);
// be equal to input size).
mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode, byte flags) {
byte *buf = buf_;
- mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(stream);
typedef mp_uint_t (*io_func_t)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
io_func_t io_func;
- const mp_stream_p_t *stream_p = s->type->protocol;
+ const mp_stream_p_t *stream_p = mp_get_stream(stream);
if (flags & MP_STREAM_RW_WRITE) {
io_func = (io_func_t)stream_p->write;
} else {
@@ -105,16 +97,7 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) {
return stream_p;
}
-mp_obj_t mp_stream_close(mp_obj_t stream) {
- // TODO: Still consider using ioctl for close
- mp_obj_t dest[2];
- mp_load_method(stream, MP_QSTR_close, dest);
- return mp_call_method_n_kw(0, 0, dest);
-}
-
STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte flags) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
-
// What to do if sz < -1? Python docs don't specify this case.
// CPython does a readall, but here we silently let negatives through,
// and they will cause a MemoryError.
@@ -123,6 +106,8 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl
return stream_readall(args[0]);
}
+ const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
+
#if MICROPY_PY_BUILTINS_STR_UNICODE
if (stream_p->is_text) {
// We need to read sz number of unicode characters. Because we don't have any
@@ -241,8 +226,6 @@ STATIC mp_obj_t stream_read1(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj, 1, 2, stream_read1);
mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte flags) {
- mp_get_stream_raise(self_in, MP_STREAM_OP_WRITE);
-
int error;
mp_uint_t out_sz = mp_stream_rw(self_in, (void*)buf, len, &error, flags);
if (error != 0) {
@@ -258,7 +241,7 @@ mp_obj_t mp_stream_write(mp_obj_t self_in, const void *buf, size_t len, byte fla
}
}
-// XXX hack
+// This is used to adapt a stream object to an mp_print_t interface
void mp_stream_write_adaptor(void *self, const char *buf, size_t len) {
mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE);
}
@@ -290,7 +273,6 @@ STATIC mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) {
MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method);
STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
- mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
@@ -319,7 +301,7 @@ STATIC mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto);
STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(self_in, MP_STREAM_OP_READ);
+ const mp_stream_p_t *stream_p = mp_get_stream(self_in);
mp_uint_t total_size = 0;
vstr_t vstr;
@@ -360,7 +342,7 @@ STATIC mp_obj_t stream_readall(mp_obj_t self_in) {
// Unbuffered, inefficient implementation of readline() for raw I/O files.
STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
+ const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
mp_int_t max_size = -1;
if (n_args > 1) {
@@ -434,9 +416,18 @@ mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) {
return MP_OBJ_STOP_ITERATION;
}
-STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL);
+mp_obj_t mp_stream_close(mp_obj_t stream) {
+ const mp_stream_p_t *stream_p = mp_get_stream(stream);
+ int error;
+ mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
+ if (res == MP_STREAM_ERROR) {
+ mp_raise_OSError(error);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close);
+STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
struct mp_stream_seek_t seek_s;
// TODO: Could be uint64
seek_s.offset = mp_obj_get_int(args[1]);
@@ -450,6 +441,7 @@ STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args) {
mp_raise_OSError(MP_EINVAL);
}
+ const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
int error;
mp_uint_t res = stream_p->ioctl(args[0], MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
if (res == MP_STREAM_ERROR) {
@@ -470,7 +462,7 @@ STATIC mp_obj_t stream_tell(mp_obj_t self) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_tell_obj, stream_tell);
STATIC mp_obj_t stream_flush(mp_obj_t self) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(self, MP_STREAM_OP_IOCTL);
+ const mp_stream_p_t *stream_p = mp_get_stream(self);
int error;
mp_uint_t res = stream_p->ioctl(self, MP_STREAM_FLUSH, 0, &error);
if (res == MP_STREAM_ERROR) {
@@ -481,8 +473,6 @@ STATIC mp_obj_t stream_flush(mp_obj_t self) {
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_flush_obj, stream_flush);
STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(args[0], MP_STREAM_OP_IOCTL);
-
mp_buffer_info_t bufinfo;
uintptr_t val = 0;
if (n_args > 2) {
@@ -493,6 +483,7 @@ STATIC mp_obj_t stream_ioctl(size_t n_args, const mp_obj_t *args) {
}
}
+ const mp_stream_p_t *stream_p = mp_get_stream(args[0]);
int error;
mp_uint_t res = stream_p->ioctl(args[0], mp_obj_get_int(args[1]), val, &error);
if (res == MP_STREAM_ERROR) {
diff --git a/py/stream.h b/py/stream.h
index fbe3d7d85..7b953138c 100644
--- a/py/stream.h
+++ b/py/stream.h
@@ -35,7 +35,7 @@
#define MP_STREAM_FLUSH (1)
#define MP_STREAM_SEEK (2)
#define MP_STREAM_POLL (3)
-//#define MP_STREAM_CLOSE (4) // Not yet implemented
+#define MP_STREAM_CLOSE (4)
#define MP_STREAM_TIMEOUT (5) // Get/set timeout (single op)
#define MP_STREAM_GET_OPTS (6) // Get stream options
#define MP_STREAM_SET_OPTS (7) // Set stream options
@@ -62,6 +62,16 @@ struct mp_stream_seek_t {
#define MP_SEEK_CUR (1)
#define MP_SEEK_END (2)
+// Stream protocol
+typedef struct _mp_stream_p_t {
+ // On error, functions should return MP_STREAM_ERROR and fill in *errcode (values
+ // are implementation-dependent, but will be exposed to user, e.g. via exception).
+ mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
+ mp_uint_t (*write)(mp_obj_t obj, const void *buf, mp_uint_t size, int *errcode);
+ mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
+ mp_uint_t is_text : 1; // default is bytes, set this for text stream
+} mp_stream_p_t;
+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj);
@@ -69,6 +79,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj);
MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj);
@@ -79,6 +90,11 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj);
#define MP_STREAM_OP_WRITE (2)
#define MP_STREAM_OP_IOCTL (4)
+// Object is assumed to have a non-NULL stream protocol with valid r/w/ioctl methods
+static inline const mp_stream_p_t *mp_get_stream(mp_const_obj_t self) {
+ return (const mp_stream_p_t*)((const mp_obj_base_t*)MP_OBJ_TO_PTR(self))->type->protocol;
+}
+
const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags);
mp_obj_t mp_stream_close(mp_obj_t stream);
@@ -106,7 +122,7 @@ int mp_stream_posix_fsync(mp_obj_t stream);
#endif
#if MICROPY_STREAMS_NON_BLOCK
-#define mp_is_nonblocking_error(errno) ((errno) == EAGAIN || (errno) == EWOULDBLOCK)
+#define mp_is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK)
#else
#define mp_is_nonblocking_error(errno) (0)
#endif
diff --git a/py/unicode.c b/py/unicode.c
index 140b7ba71..935dc9012 100644
--- a/py/unicode.c
+++ b/py/unicode.c
@@ -67,9 +67,9 @@ STATIC const uint8_t attr[] = {
AT_LO, AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0
};
-// TODO: Rename to str_get_char
-unichar utf8_get_char(const byte *s) {
#if MICROPY_PY_BUILTINS_STR_UNICODE
+
+unichar utf8_get_char(const byte *s) {
unichar ord = *s++;
if (!UTF8_IS_NONASCII(ord)) return ord;
ord &= 0x7F;
@@ -80,22 +80,14 @@ unichar utf8_get_char(const byte *s) {
ord = (ord << 6) | (*s++ & 0x3F);
}
return ord;
-#else
- return *s;
-#endif
}
-// TODO: Rename to str_next_char
const byte *utf8_next_char(const byte *s) {
-#if MICROPY_PY_BUILTINS_STR_UNICODE
++s;
while (UTF8_IS_CONT(*s)) {
++s;
}
return s;
-#else
- return s + 1;
-#endif
}
mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) {
@@ -109,21 +101,18 @@ mp_uint_t utf8_ptr_to_index(const byte *s, const byte *ptr) {
return i;
}
-// TODO: Rename to str_charlen
-mp_uint_t unichar_charlen(const char *str, mp_uint_t len) {
-#if MICROPY_PY_BUILTINS_STR_UNICODE
- mp_uint_t charlen = 0;
- for (const char *top = str + len; str < top; ++str) {
+size_t utf8_charlen(const byte *str, size_t len) {
+ size_t charlen = 0;
+ for (const byte *top = str + len; str < top; ++str) {
if (!UTF8_IS_CONT(*str)) {
++charlen;
}
}
return charlen;
-#else
- return len;
-#endif
}
+#endif
+
// Be aware: These unichar_is* functions are actually ASCII-only!
bool unichar_isspace(unichar c) {
return c < 128 && (attr[c] & FL_SPACE) != 0;
@@ -183,6 +172,8 @@ mp_uint_t unichar_xdigit_value(unichar c) {
return n;
}
+#if MICROPY_PY_BUILTINS_STR_UNICODE
+
bool utf8_check(const byte *p, size_t len) {
uint8_t need = 0;
const byte *end = p + len;
@@ -210,3 +201,5 @@ bool utf8_check(const byte *p, size_t len) {
}
return need == 0; // no pending fragments allowed
}
+
+#endif
diff --git a/py/vm.c b/py/vm.c
index 564200037..498ecb491 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -48,14 +48,6 @@
// top element.
// Exception stack also grows up, top element is also pointed at.
-// Exception stack unwind reasons (WHY_* in CPython-speak)
-// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
-// left to do encoded in the JUMP number
-typedef enum {
- UNWIND_RETURN = 1,
- UNWIND_JUMP,
-} mp_unwind_reason_t;
-
#define DECODE_UINT \
mp_uint_t unum = 0; \
do { \
@@ -144,7 +136,7 @@ mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp
#define ENTRY(op) entry_##op
#define ENTRY_DEFAULT entry_default
#else
- #define DISPATCH() break
+ #define DISPATCH() goto dispatch_loop
#define DISPATCH_WITH_PEND_EXC_CHECK() goto pending_exception_check
#define ENTRY(op) case op
#define ENTRY_DEFAULT default
@@ -344,7 +336,7 @@ dispatch_loop:
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_obj_t top = TOP();
- if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) {
+ if (mp_obj_is_instance_type(mp_obj_get_type(top))) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
mp_uint_t x = *ip;
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
@@ -442,7 +434,7 @@ dispatch_loop:
MARK_EXC_IP_SELECTIVE();
DECODE_QSTR;
mp_obj_t top = TOP();
- if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) {
+ if (mp_obj_is_instance_type(mp_obj_get_type(top)) && sp[-1] != MP_OBJ_NULL) {
mp_obj_instance_t *self = MP_OBJ_TO_PTR(top);
mp_uint_t x = *ip;
mp_obj_t key = MP_OBJ_NEW_QSTR(qst);
@@ -613,29 +605,18 @@ dispatch_loop:
mp_call_method_n_kw(3, 0, sp);
SET_TOP(mp_const_none);
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
- mp_int_t cause_val = MP_OBJ_SMALL_INT_VALUE(TOP());
- if (cause_val == UNWIND_RETURN) {
- // stack: (..., __exit__, ctx_mgr, ret_val, UNWIND_RETURN)
- mp_obj_t ret_val = sp[-1];
- sp[-1] = mp_const_none;
- sp[0] = mp_const_none;
- sp[1] = mp_const_none;
- mp_call_method_n_kw(3, 0, sp - 3);
- sp[-3] = ret_val;
- sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN);
- } else {
- assert(cause_val == UNWIND_JUMP);
- // stack: (..., __exit__, ctx_mgr, dest_ip, num_exc, UNWIND_JUMP)
- mp_obj_t dest_ip = sp[-2];
- mp_obj_t num_exc = sp[-1];
- sp[-2] = mp_const_none;
- sp[-1] = mp_const_none;
- sp[0] = mp_const_none;
- mp_call_method_n_kw(3, 0, sp - 4);
- sp[-4] = dest_ip;
- sp[-3] = num_exc;
- sp[-2] = MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP);
- }
+ // Getting here there are two distinct cases:
+ // - unwind return, stack: (..., __exit__, ctx_mgr, ret_val, SMALL_INT(-1))
+ // - unwind jump, stack: (..., __exit__, ctx_mgr, dest_ip, SMALL_INT(num_exc))
+ // For both cases we do exactly the same thing.
+ mp_obj_t data = sp[-1];
+ mp_obj_t cause = sp[0];
+ sp[-1] = mp_const_none;
+ sp[0] = mp_const_none;
+ sp[1] = mp_const_none;
+ mp_call_method_n_kw(3, 0, sp - 3);
+ sp[-3] = data;
+ sp[-2] = cause;
sp -= 2; // we removed (__exit__, ctx_mgr)
} else {
assert(mp_obj_is_exception_instance(TOP()));
@@ -680,10 +661,11 @@ unwind_jump:;
// of a "with" block contains the context manager info.
// We're going to run "finally" code as a coroutine
// (not calling it recursively). Set up a sentinel
- // on a stack so it can return back to us when it is
+ // on the stack so it can return back to us when it is
// done (when WITH_CLEANUP or END_FINALLY reached).
- PUSH((mp_obj_t)unum); // push number of exception handlers left to unwind
- PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_JUMP)); // push sentinel
+ // The sentinel is the number of exception handlers left to
+ // unwind, which is a non-negative integer.
+ PUSH(MP_OBJ_NEW_SMALL_INT(unum));
ip = exc_sp->handler; // get exception handler byte code address
exc_sp--; // pop exception handler
goto dispatch_loop; // run the exception handler
@@ -720,11 +702,14 @@ unwind_jump:;
} else if (MP_OBJ_IS_SMALL_INT(TOP())) {
// We finished "finally" coroutine and now dispatch back
// to our caller, based on TOS value
- mp_unwind_reason_t reason = MP_OBJ_SMALL_INT_VALUE(POP());
- if (reason == UNWIND_RETURN) {
+ mp_int_t cause = MP_OBJ_SMALL_INT_VALUE(POP());
+ if (cause < 0) {
+ // A negative cause indicates unwind return
goto unwind_return;
} else {
- assert(reason == UNWIND_JUMP);
+ // Otherwise it's an unwind jump and we must push as a raw
+ // number the number of exception handlers to unwind
+ PUSH((mp_obj_t)cause);
goto unwind_jump;
}
} else {
@@ -926,18 +911,22 @@ unwind_jump:;
code_state->sp = sp;
code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block);
mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1);
- if (new_state) {
+ #if !MICROPY_ENABLE_PYSTACK
+ if (new_state == NULL) {
+ // Couldn't allocate codestate on heap: in the strict case raise
+ // an exception, otherwise just fall through to stack allocation.
+ #if MICROPY_STACKLESS_STRICT
+ deep_recursion_error:
+ mp_raise_recursion_depth();
+ #endif
+ } else
+ #endif
+ {
new_state->prev = code_state;
code_state = new_state;
nlr_pop();
goto run_code_state;
}
- #if MICROPY_STACKLESS_STRICT
- else {
- deep_recursion_error:
- mp_exc_recursion_depth();
- }
- #endif
}
#endif
SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));
@@ -963,18 +952,26 @@ unwind_jump:;
mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun,
out_args.n_args, out_args.n_kw, out_args.args);
- m_del(mp_obj_t, out_args.args, out_args.n_alloc);
- if (new_state) {
+ #if !MICROPY_ENABLE_PYSTACK
+ // Freeing args at this point does not follow a LIFO order so only do it if
+ // pystack is not enabled. For pystack, they are freed when code_state is.
+ mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));
+ #endif
+ #if !MICROPY_ENABLE_PYSTACK
+ if (new_state == NULL) {
+ // Couldn't allocate codestate on heap: in the strict case raise
+ // an exception, otherwise just fall through to stack allocation.
+ #if MICROPY_STACKLESS_STRICT
+ goto deep_recursion_error;
+ #endif
+ } else
+ #endif
+ {
new_state->prev = code_state;
code_state = new_state;
nlr_pop();
goto run_code_state;
}
- #if MICROPY_STACKLESS_STRICT
- else {
- goto deep_recursion_error;
- }
- #endif
}
#endif
SET_TOP(mp_call_method_n_kw_var(false, unum, sp));
@@ -998,17 +995,21 @@ unwind_jump:;
int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1;
mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust);
- if (new_state) {
+ #if !MICROPY_ENABLE_PYSTACK
+ if (new_state == NULL) {
+ // Couldn't allocate codestate on heap: in the strict case raise
+ // an exception, otherwise just fall through to stack allocation.
+ #if MICROPY_STACKLESS_STRICT
+ goto deep_recursion_error;
+ #endif
+ } else
+ #endif
+ {
new_state->prev = code_state;
code_state = new_state;
nlr_pop();
goto run_code_state;
}
- #if MICROPY_STACKLESS_STRICT
- else {
- goto deep_recursion_error;
- }
- #endif
}
#endif
SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));
@@ -1034,18 +1035,26 @@ unwind_jump:;
mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun,
out_args.n_args, out_args.n_kw, out_args.args);
- m_del(mp_obj_t, out_args.args, out_args.n_alloc);
- if (new_state) {
+ #if !MICROPY_ENABLE_PYSTACK
+ // Freeing args at this point does not follow a LIFO order so only do it if
+ // pystack is not enabled. For pystack, they are freed when code_state is.
+ mp_nonlocal_free(out_args.args, out_args.n_alloc * sizeof(mp_obj_t));
+ #endif
+ #if !MICROPY_ENABLE_PYSTACK
+ if (new_state == NULL) {
+ // Couldn't allocate codestate on heap: in the strict case raise
+ // an exception, otherwise just fall through to stack allocation.
+ #if MICROPY_STACKLESS_STRICT
+ goto deep_recursion_error;
+ #endif
+ } else
+ #endif
+ {
new_state->prev = code_state;
code_state = new_state;
nlr_pop();
goto run_code_state;
}
- #if MICROPY_STACKLESS_STRICT
- else {
- goto deep_recursion_error;
- }
- #endif
}
#endif
SET_TOP(mp_call_method_n_kw_var(true, unum, sp));
@@ -1081,7 +1090,7 @@ unwind_return:
// (not calling it recursively). Set up a sentinel
// on a stack so it can return back to us when it is
// done (when WITH_CLEANUP or END_FINALLY reached).
- PUSH(MP_OBJ_NEW_SMALL_INT(UNWIND_RETURN));
+ PUSH(MP_OBJ_NEW_SMALL_INT(-1));
ip = exc_sp->handler;
exc_sp--;
goto dispatch_loop;
@@ -1096,7 +1105,15 @@ unwind_return:
if (code_state->prev != NULL) {
mp_obj_t res = *sp;
mp_globals_set(code_state->old_globals);
- code_state = code_state->prev;
+ mp_code_state_t *new_code_state = code_state->prev;
+ #if MICROPY_ENABLE_PYSTACK
+ // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var
+ // (The latter is implicitly freed when using pystack due to its LIFO nature.)
+ // The sizeof in the following statement does not include the size of the variable
+ // part of the struct. This arg is anyway not used if pystack is enabled.
+ mp_nonlocal_free(code_state, sizeof(mp_code_state_t));
+ #endif
+ code_state = new_code_state;
*code_state->sp = res;
goto run_code_state;
}
@@ -1105,7 +1122,7 @@ unwind_return:
ENTRY(MP_BC_RAISE_VARARGS): {
MARK_EXC_IP_SELECTIVE();
- mp_uint_t unum = *ip++;
+ mp_uint_t unum = *ip;
mp_obj_t obj;
if (unum == 2) {
mp_warning("exception chaining not supported");
@@ -1126,7 +1143,7 @@ unwind_return:
RAISE(obj);
}
} else {
- obj = POP();
+ obj = TOP();
}
obj = mp_make_raise_obj(obj);
RAISE(obj);
@@ -1149,6 +1166,7 @@ yield:
mp_obj_t send_value = POP();
mp_obj_t t_exc = MP_OBJ_NULL;
mp_obj_t ret_value;
+ code_state->sp = sp; // Save sp because it's needed if mp_resume raises StopIteration
if (inject_exc != MP_OBJ_NULL) {
t_exc = inject_exc;
inject_exc = MP_OBJ_NULL;
@@ -1164,8 +1182,7 @@ yield:
} else if (ret_kind == MP_VM_RETURN_NORMAL) {
// Pop exhausted gen
sp--;
- // TODO: When ret_value can be MP_OBJ_NULL here??
- if (ret_value == MP_OBJ_NULL || ret_value == MP_OBJ_STOP_ITERATION) {
+ if (ret_value == MP_OBJ_STOP_ITERATION) {
// Optimize StopIteration
// TODO: get StopIteration's value
PUSH(mp_const_none);
@@ -1253,10 +1270,10 @@ yield:
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
fastn[MP_BC_STORE_FAST_MULTI - (mp_int_t)ip[-1]] = POP();
DISPATCH();
- } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 7) {
+ } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
DISPATCH();
- } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) {
+ } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
@@ -1305,11 +1322,12 @@ pending_exception_check:
#if MICROPY_PY_THREAD_GIL
#if MICROPY_PY_THREAD_GIL_VM_DIVISOR
- if (--gil_divisor == 0) {
- gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;
- #else
- {
+ if (--gil_divisor == 0)
#endif
+ {
+ #if MICROPY_PY_THREAD_GIL_VM_DIVISOR
+ gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;
+ #endif
#if MICROPY_ENABLE_SCHEDULER
// can only switch threads if the scheduler is unlocked
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE)
@@ -1348,7 +1366,8 @@ exception_handler:
} else if (*code_state->ip == MP_BC_YIELD_FROM) {
// StopIteration inside yield from call means return a value of
// yield from, so inject exception's value as yield from's result
- *++code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));
+ // (Instead of stack pop then push we just replace exhausted gen with value)
+ *code_state->sp = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val));
code_state->ip++; // yield from is over, move to next instruction
goto outer_dispatch_loop; // continue with dispatch loop
}
@@ -1361,8 +1380,7 @@ unwind_loop:
// set file and line number that the exception occurred at
// TODO: don't set traceback for exceptions re-raised by END_FINALLY.
// But consider how to handle nested exceptions.
- // TODO need a better way of not adding traceback to constant objects (right now, just GeneratorExit_obj and MemoryError_obj)
- if (nlr.ret_val != &mp_const_GeneratorExit_obj && nlr.ret_val != &mp_const_MemoryError_obj) {
+ if (nlr.ret_val != &mp_const_GeneratorExit_obj) {
const byte *ip = code_state->fun_bc->bytecode;
ip = mp_decode_uint_skip(ip); // skip n_state
ip = mp_decode_uint_skip(ip); // skip n_exc_stack
@@ -1438,7 +1456,15 @@ unwind_loop:
#if MICROPY_STACKLESS
} else if (code_state->prev != NULL) {
mp_globals_set(code_state->old_globals);
- code_state = code_state->prev;
+ mp_code_state_t *new_code_state = code_state->prev;
+ #if MICROPY_ENABLE_PYSTACK
+ // Free code_state, and args allocated by mp_call_prepare_args_n_kw_var
+ // (The latter is implicitly freed when using pystack due to its LIFO nature.)
+ // The sizeof in the following statement does not include the size of the variable
+ // part of the struct. This arg is anyway not used if pystack is enabled.
+ mp_nonlocal_free(code_state, sizeof(mp_code_state_t));
+ #endif
+ code_state = new_code_state;
size_t n_state = mp_decode_uint_value(code_state->fun_bc->bytecode);
fastn = &code_state->state[n_state - 1];
exc_stack = (mp_exc_stack_t*)(code_state->state + n_state);