2013-10-04 14:53:11 -04:00
# include <stdio.h>
# include <assert.h>
2013-10-15 17:25:17 -04:00
# include "nlr.h"
2013-10-04 14:53:11 -04:00
# include "misc.h"
2013-12-21 13:17:45 -05:00
# include "mpconfig.h"
2014-01-21 16:40:13 -05:00
# include "qstr.h"
2013-12-21 13:17:45 -05:00
# include "obj.h"
2013-10-04 14:53:11 -04:00
# include "runtime.h"
2013-12-21 13:17:45 -05:00
# include "bc0.h"
2013-10-10 17:06:54 -04:00
# include "bc.h"
2013-10-04 14:53:11 -04:00
2014-01-31 12:45:15 -05:00
// Value stack grows up (this makes it incompatible with native C stack, but
// makes sure that arguments to functions are in natural order arg1..argN
// (Python semantics mandates left-to-right evaluation order, including for
// function arguments). Stack pointer is pre-incremented and points at the
// top element.
// Exception stack also grows up, top element is also pointed at.
2014-01-31 17:55:05 -05:00
// Exception stack unwind reasons (WHY_* in CPython-speak)
2014-02-01 15:08:18 -05:00
// TODO perhaps compress this to RETURN=0, JUMP>0, with number of unwinds
// left to do encoded in the JUMP number
2014-01-31 17:55:05 -05:00
typedef enum {
UNWIND_RETURN = 1 ,
2014-02-01 15:08:18 -05:00
UNWIND_JUMP ,
2014-01-31 17:55:05 -05:00
} mp_unwind_reason_t ;
2014-02-18 14:21:22 -05:00
# define DECODE_UINT { \
unum = 0 ; \
do { \
unum = ( unum < < 7 ) + ( * ip & 0x7f ) ; \
} while ( ( * ip + + & 0x80 ) ! = 0 ) ; \
}
2013-11-05 17:06:08 -05:00
# define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0)
# define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0)
2014-02-18 14:21:22 -05:00
# define DECODE_QSTR { \
qst = 0 ; \
do { \
qst = ( qst < < 7 ) + ( * ip & 0x7f ) ; \
} while ( ( * ip + + & 0x80 ) ! = 0 ) ; \
}
2014-01-18 09:10:48 -05:00
# define PUSH(val) *++sp = (val)
# define POP() (*sp--)
2013-12-10 12:27:24 -05:00
# define TOP() (*sp)
# define SET_TOP(val) *sp = (val)
2013-10-04 14:53:11 -04:00
2014-02-15 17:55:00 -05:00
mp_vm_return_kind_t mp_execute_byte_code ( const byte * code , const mp_obj_t * args , uint n_args , const mp_obj_t * args2 , uint n_args2 , uint n_state , mp_obj_t * ret ) {
2014-01-18 09:10:48 -05:00
// allocate state for locals and stack
mp_obj_t temp_state [ 10 ] ;
2013-12-21 13:17:45 -05:00
mp_obj_t * state = & temp_state [ 0 ] ;
2013-11-05 17:16:22 -05:00
if ( n_state > 10 ) {
2013-12-21 13:17:45 -05:00
state = m_new ( mp_obj_t , n_state ) ;
2013-11-05 17:16:22 -05:00
}
2014-01-18 09:10:48 -05:00
mp_obj_t * sp = & state [ 0 ] - 1 ;
2013-10-16 15:39:12 -04:00
// init args
2014-02-01 13:29:40 -05:00
for ( uint i = 0 ; i < n_args ; i + + ) {
2014-01-18 09:10:48 -05:00
state [ n_state - 1 - i ] = args [ i ] ;
2013-10-16 15:39:12 -04:00
}
2014-02-01 13:29:40 -05:00
for ( uint i = 0 ; i < n_args2 ; i + + ) {
state [ n_state - 1 - n_args - i ] = args2 [ i ] ;
}
2014-01-18 18:24:36 -05:00
2013-10-16 15:39:12 -04:00
const byte * ip = code ;
2013-12-30 17:32:17 -05:00
2014-01-18 18:24:36 -05:00
// get code info size
machine_uint_t code_info_size = ip [ 0 ] | ( ip [ 1 ] < < 8 ) | ( ip [ 2 ] < < 16 ) | ( ip [ 3 ] < < 24 ) ;
ip + = code_info_size ;
2013-12-30 17:32:17 -05:00
// execute prelude to make any cells (closed over variables)
{
for ( uint n_local = * ip + + ; n_local > 0 ; n_local - - ) {
uint local_num = * ip + + ;
2014-02-01 13:29:40 -05:00
if ( local_num < n_args + n_args2 ) {
2014-01-18 09:10:48 -05:00
state [ n_state - 1 - local_num ] = mp_obj_new_cell ( state [ n_state - 1 - local_num ] ) ;
2013-12-30 17:32:17 -05:00
} else {
2014-01-18 09:10:48 -05:00
state [ n_state - 1 - local_num ] = mp_obj_new_cell ( MP_OBJ_NULL ) ;
2013-12-30 17:32:17 -05:00
}
}
}
2014-03-22 07:49:31 -04:00
mp_exc_stack exc_stack [ 4 ] ;
mp_exc_stack * exc_sp = & exc_stack [ 0 ] - 1 ;
2013-12-30 17:32:17 -05:00
// execute the byte code
2014-03-22 11:50:12 -04:00
mp_vm_return_kind_t vm_return_kind = mp_execute_byte_code_2 ( code , & ip , & state [ n_state - 1 ] , & sp , exc_stack , & exc_sp , MP_OBJ_NULL ) ;
2014-02-15 17:55:00 -05:00
switch ( vm_return_kind ) {
case MP_VM_RETURN_NORMAL :
* ret = * sp ;
return MP_VM_RETURN_NORMAL ;
case MP_VM_RETURN_EXCEPTION :
* ret = state [ n_state - 1 ] ;
return MP_VM_RETURN_EXCEPTION ;
case MP_VM_RETURN_YIELD : // byte-code shouldn't yield
default :
assert ( 0 ) ;
* ret = mp_const_none ;
return MP_VM_RETURN_NORMAL ;
2013-10-16 15:39:12 -04:00
}
}
2014-01-18 09:10:48 -05:00
// fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc)
// sp points to bottom of stack which grows up
2014-02-15 17:55:00 -05:00
// returns:
// MP_VM_RETURN_NORMAL, sp valid, return value in *sp
// MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp
// MP_VM_RETURN_EXCEPTION, exception in fastn[0]
2014-03-22 07:49:31 -04:00
mp_vm_return_kind_t mp_execute_byte_code_2 ( const byte * code_info , const byte * * ip_in_out ,
mp_obj_t * fastn , mp_obj_t * * sp_in_out ,
2014-03-22 11:50:12 -04:00
mp_exc_stack * exc_stack , mp_exc_stack * * exc_sp_in_out ,
volatile mp_obj_t inject_exc ) {
2013-10-15 18:46:01 -04:00
// careful: be sure to declare volatile any variables read in the exception handler (written is ok, I think)
2013-10-16 15:39:12 -04:00
const byte * ip = * ip_in_out ;
2013-12-21 13:17:45 -05:00
mp_obj_t * sp = * sp_in_out ;
2013-10-04 14:53:11 -04:00
machine_uint_t unum ;
2014-01-19 06:48:48 -05:00
qstr qst ;
2013-12-21 13:17:45 -05:00
mp_obj_t obj1 , obj2 ;
2013-10-15 17:25:17 -04:00
nlr_buf_t nlr ;
2013-10-04 14:53:11 -04:00
2014-03-22 17:20:07 -04:00
volatile bool currently_in_except_block = MP_TAGPTR_TAG ( * exc_sp_in_out ) ; // 0 or 1, to detect nested exceptions
mp_exc_stack * volatile exc_sp = MP_TAGPTR_PTR ( * exc_sp_in_out ) ; // stack grows up, exc_sp points to top of stack
2014-01-18 18:24:36 -05:00
const byte * volatile save_ip = ip ; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
2013-10-15 18:46:01 -04:00
2013-10-15 17:25:17 -04:00
// outer exception handling loop
2013-10-04 14:53:11 -04:00
for ( ; ; ) {
2014-03-26 14:37:06 -04:00
outer_dispatch_loop :
2013-10-15 17:25:17 -04:00
if ( nlr_push ( & nlr ) = = 0 ) {
2014-03-22 11:50:12 -04:00
// If we have exception to inject, now that we finish setting up
// execution context, raise it. This works as if RAISE_VARARGS
// bytecode was executed.
if ( inject_exc ! = MP_OBJ_NULL ) {
mp_obj_t t = inject_exc ;
inject_exc = MP_OBJ_NULL ;
nlr_jump ( rt_make_raise_obj ( t ) ) ;
}
2013-10-15 17:25:17 -04:00
// loop to execute byte code
for ( ; ; ) {
2014-01-31 17:55:05 -05:00
dispatch_loop :
2014-01-18 18:24:36 -05:00
save_ip = ip ;
2013-10-15 17:25:17 -04:00
int op = * ip + + ;
switch ( op ) {
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_FALSE :
PUSH ( mp_const_false ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_NONE :
PUSH ( mp_const_none ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_TRUE :
PUSH ( mp_const_true ) ;
2013-10-15 17:25:17 -04:00
break ;
2014-01-04 13:44:46 -05:00
case MP_BC_LOAD_CONST_ELLIPSIS :
PUSH ( mp_const_ellipsis ) ;
break ;
2013-10-15 17:25:17 -04:00
2014-02-19 08:47:59 -05:00
case MP_BC_LOAD_CONST_SMALL_INT : {
2014-02-19 19:00:04 -05:00
machine_int_t num = 0 ;
2014-02-19 08:47:59 -05:00
if ( ( ip [ 0 ] & 0x40 ) ! = 0 ) {
// Number is negative
num - - ;
}
do {
num = ( num < < 7 ) | ( * ip & 0x7f ) ;
} while ( ( * ip + + & 0x80 ) ! = 0 ) ;
PUSH ( MP_OBJ_NEW_SMALL_INT ( num ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2014-02-19 08:47:59 -05:00
}
2013-10-15 17:25:17 -04:00
2014-01-17 12:51:46 -05:00
case MP_BC_LOAD_CONST_INT :
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( mp_obj_new_int_from_long_str ( qstr_str ( qst ) ) ) ;
2014-01-17 12:51:46 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_DEC :
2013-11-02 15:47:57 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( rt_load_const_dec ( qst ) ) ;
2013-11-02 15:47:57 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_ID :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( rt_load_const_str ( qst ) ) ; // TODO
2013-10-15 17:25:17 -04:00
break ;
2014-01-02 11:46:27 -05:00
case MP_BC_LOAD_CONST_BYTES :
DECODE_QSTR ;
2014-01-24 15:50:40 -05:00
PUSH ( rt_load_const_bytes ( qst ) ) ;
2014-01-02 11:46:27 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_CONST_STRING :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( rt_load_const_str ( qst ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_FAST_0 :
2014-01-29 15:30:52 -05:00
PUSH ( fastn [ 0 ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_FAST_1 :
2014-01-29 15:30:52 -05:00
PUSH ( fastn [ - 1 ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_FAST_2 :
2014-01-29 15:30:52 -05:00
PUSH ( fastn [ - 2 ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_FAST_N :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
PUSH ( fastn [ - unum ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_DEREF :
2013-12-10 19:41:43 -05:00
DECODE_UINT ;
2014-01-29 15:30:52 -05:00
PUSH ( rt_get_cell ( fastn [ - unum ] ) ) ;
2013-12-10 19:41:43 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_NAME :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( rt_load_name ( qst ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_GLOBAL :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
PUSH ( rt_load_global ( qst ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_ATTR :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
SET_TOP ( rt_load_attr ( TOP ( ) , qst ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_METHOD :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
rt_load_method ( * sp , qst , sp ) ;
2014-01-18 09:10:48 -05:00
sp + = 1 ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LOAD_BUILD_CLASS :
2013-10-15 17:25:17 -04:00
PUSH ( rt_load_build_class ( ) ) ;
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_FAST_0 :
2014-01-29 15:30:52 -05:00
fastn [ 0 ] = POP ( ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_FAST_1 :
2014-01-29 15:30:52 -05:00
fastn [ - 1 ] = POP ( ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_FAST_2 :
2014-01-29 15:30:52 -05:00
fastn [ - 2 ] = POP ( ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_FAST_N :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
fastn [ - unum ] = POP ( ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_DEREF :
2013-12-10 19:41:43 -05:00
DECODE_UINT ;
2014-01-29 15:30:52 -05:00
rt_set_cell ( fastn [ - unum ] , POP ( ) ) ;
2013-12-10 19:41:43 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_NAME :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
rt_store_name ( qst , POP ( ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_GLOBAL :
2013-11-04 18:04:50 -05:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
rt_store_global ( qst , POP ( ) ) ;
2013-11-04 18:04:50 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_ATTR :
2013-10-15 17:25:17 -04:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
rt_store_attr ( sp [ 0 ] , qst , sp [ - 1 ] ) ;
2014-01-18 09:10:48 -05:00
sp - = 2 ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_SUBSCR :
2014-01-18 09:10:48 -05:00
rt_store_subscr ( sp [ - 1 ] , sp [ 0 ] , sp [ - 2 ] ) ;
sp - = 3 ;
2013-10-15 17:25:17 -04:00
break ;
2014-03-23 15:19:02 -04:00
case MP_BC_DELETE_NAME :
DECODE_QSTR ;
rt_delete_name ( qst ) ;
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_DUP_TOP :
2013-12-10 12:27:24 -05:00
obj1 = TOP ( ) ;
2013-10-15 17:25:17 -04:00
PUSH ( obj1 ) ;
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_DUP_TOP_TWO :
2014-01-18 09:10:48 -05:00
sp + = 2 ;
sp [ 0 ] = sp [ - 2 ] ;
sp [ - 1 ] = sp [ - 3 ] ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_POP_TOP :
2014-01-18 09:10:48 -05:00
sp - = 1 ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_ROT_TWO :
2013-11-02 10:33:10 -04:00
obj1 = sp [ 0 ] ;
2014-01-18 09:10:48 -05:00
sp [ 0 ] = sp [ - 1 ] ;
sp [ - 1 ] = obj1 ;
2013-11-02 10:33:10 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_ROT_THREE :
2013-10-15 17:25:17 -04:00
obj1 = sp [ 0 ] ;
2014-01-18 09:10:48 -05:00
sp [ 0 ] = sp [ - 1 ] ;
sp [ - 1 ] = sp [ - 2 ] ;
sp [ - 2 ] = obj1 ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_JUMP :
2013-11-05 17:06:08 -05:00
DECODE_SLABEL ;
ip + = unum ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_POP_JUMP_IF_TRUE :
2013-11-05 17:06:08 -05:00
DECODE_SLABEL ;
2013-10-15 17:25:17 -04:00
if ( rt_is_true ( POP ( ) ) ) {
2013-11-05 17:06:08 -05:00
ip + = unum ;
2013-10-15 17:25:17 -04:00
}
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_POP_JUMP_IF_FALSE :
2013-11-05 17:06:08 -05:00
DECODE_SLABEL ;
2013-10-15 17:25:17 -04:00
if ( ! rt_is_true ( POP ( ) ) ) {
2013-11-05 17:06:08 -05:00
ip + = unum ;
2013-10-15 17:25:17 -04:00
}
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_JUMP_IF_TRUE_OR_POP :
2013-11-09 15:12:32 -05:00
DECODE_SLABEL ;
2013-12-10 12:27:24 -05:00
if ( rt_is_true ( TOP ( ) ) ) {
2013-11-09 15:12:32 -05:00
ip + = unum ;
} else {
2014-01-18 09:10:48 -05:00
sp - - ;
2013-11-09 15:12:32 -05:00
}
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_JUMP_IF_FALSE_OR_POP :
2013-11-09 15:12:32 -05:00
DECODE_SLABEL ;
2013-12-10 12:27:24 -05:00
if ( rt_is_true ( TOP ( ) ) ) {
2014-01-18 09:10:48 -05:00
sp - - ;
2013-11-09 15:12:32 -05:00
} else {
ip + = unum ;
}
break ;
2013-10-15 17:25:17 -04:00
/* we are trying to get away without using this opcode
2013-12-21 13:17:45 -05:00
case MP_BC_SETUP_LOOP :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2013-12-21 13:17:45 -05:00
// push_block(MP_BC_SETUP_LOOP, ip + unum, sp)
2013-10-15 17:25:17 -04:00
break ;
*/
2014-02-01 15:08:18 -05:00
case MP_BC_UNWIND_JUMP :
DECODE_SLABEL ;
PUSH ( ( void * ) ( ip + unum ) ) ; // push destination ip for jump
PUSH ( ( void * ) ( machine_uint_t ) ( * ip ) ) ; // push number of exception handlers to unwind
unwind_jump :
unum = ( machine_uint_t ) POP ( ) ; // get number of exception handlers to unwind
while ( unum > 0 ) {
unum - = 1 ;
assert ( exc_sp > = exc_stack ) ;
if ( exc_sp - > opcode = = MP_BC_SETUP_FINALLY ) {
// 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
// done (when END_FINALLY reached).
PUSH ( ( void * ) unum ) ; // push number of exception handlers left to unwind
PUSH ( MP_OBJ_NEW_SMALL_INT ( UNWIND_JUMP ) ) ; // push sentinel
ip = exc_sp - > handler ; // get exception handler byte code address
exc_sp - - ; // pop exception handler
goto dispatch_loop ; // run the exception handler
}
exc_sp - - ;
}
ip = ( const byte * ) POP ( ) ; // pop destination ip for jump
2014-01-21 18:48:04 -05:00
break ;
2013-12-29 13:48:37 -05:00
// matched against: POP_BLOCK or POP_EXCEPT (anything else?)
2013-12-21 13:17:45 -05:00
case MP_BC_SETUP_EXCEPT :
2014-01-31 12:40:09 -05:00
case MP_BC_SETUP_FINALLY :
2013-11-05 17:06:08 -05:00
DECODE_ULABEL ; // except labels are always forward
2014-01-31 12:40:09 -05:00
+ + exc_sp ;
exc_sp - > opcode = op ;
exc_sp - > handler = ip + unum ;
2014-03-22 17:20:07 -04:00
exc_sp - > val_sp = MP_TAGPTR_MAKE ( sp , currently_in_except_block ) ;
2013-12-29 11:54:59 -05:00
currently_in_except_block = 0 ; // in a try block now
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_END_FINALLY :
2014-01-30 06:49:18 -05:00
// not fully implemented
2013-10-15 17:25:17 -04:00
// if TOS is an exception, reraises the exception (3 values on TOS)
// if TOS is None, just pops it and continues
2014-01-30 06:49:18 -05:00
// if TOS is an integer, does something else
2013-10-15 17:25:17 -04:00
// else error
2014-02-15 11:10:44 -05:00
if ( mp_obj_is_exception_instance ( TOP ( ) ) ) {
2014-01-30 06:49:18 -05:00
nlr_jump ( TOP ( ) ) ;
}
if ( TOP ( ) = = mp_const_none ) {
sp - - ;
2014-01-31 17:55:05 -05:00
} 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 ( ) ) ;
switch ( reason ) {
case UNWIND_RETURN :
goto unwind_return ;
2014-02-01 15:08:18 -05:00
case UNWIND_JUMP :
goto unwind_jump ;
2014-01-31 17:55:05 -05:00
}
assert ( 0 ) ;
2014-01-30 06:49:18 -05:00
} else {
assert ( 0 ) ;
}
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_GET_ITER :
2013-12-10 12:27:24 -05:00
SET_TOP ( rt_getiter ( TOP ( ) ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_FOR_ITER :
2013-11-05 17:06:08 -05:00
DECODE_ULABEL ; // the jump offset if iteration finishes; for labels are always forward
2014-03-26 15:27:58 -04:00
obj1 = rt_iternext_allow_raise ( TOP ( ) ) ;
if ( obj1 = = MP_OBJ_NULL ) {
2014-01-18 09:10:48 -05:00
- - sp ; // pop the exhausted iterator
2013-11-05 17:06:08 -05:00
ip + = unum ; // jump to after for-block
2013-10-15 17:25:17 -04:00
} else {
PUSH ( obj1 ) ; // push the next iteration value
}
break ;
2013-12-29 13:48:37 -05:00
// matched against: SETUP_EXCEPT, SETUP_FINALLY, SETUP_WITH
2013-12-21 13:17:45 -05:00
case MP_BC_POP_BLOCK :
2013-12-29 13:48:37 -05:00
// we are exiting an exception handler, so pop the last one of the exception-stack
2014-03-22 07:49:31 -04:00
assert ( exc_sp > = exc_stack ) ;
2014-03-22 17:20:07 -04:00
currently_in_except_block = MP_TAGPTR_TAG ( exc_sp - > val_sp ) ; // restore previous state
2014-01-31 12:40:09 -05:00
exc_sp - - ; // pop back to previous exception handler
2013-10-15 17:25:17 -04:00
break ;
2014-01-21 18:48:04 -05:00
// matched against: SETUP_EXCEPT
2013-12-21 13:17:45 -05:00
case MP_BC_POP_EXCEPT :
2013-10-15 18:46:01 -04:00
// TODO need to work out how blocks work etc
2013-10-15 17:25:17 -04:00
// pops block, checks it's an exception block, and restores the stack, saving the 3 exception values to local threadstate
2014-03-22 07:49:31 -04:00
assert ( exc_sp > = exc_stack ) ;
2014-01-30 06:49:18 -05:00
assert ( currently_in_except_block ) ;
2013-12-21 13:17:45 -05:00
//sp = (mp_obj_t*)(*exc_sp--);
2013-10-15 18:46:01 -04:00
//exc_sp--; // discard ip
2014-03-22 17:20:07 -04:00
currently_in_except_block = MP_TAGPTR_TAG ( exc_sp - > val_sp ) ; // restore previous state
2014-01-31 12:40:09 -05:00
exc_sp - - ; // pop back to previous exception handler
2014-01-18 09:10:48 -05:00
//sp -= 3; // pop 3 exception values
2013-10-15 17:25:17 -04:00
break ;
2014-02-01 18:04:09 -05:00
case MP_BC_NOT :
if ( TOP ( ) = = mp_const_true ) {
SET_TOP ( mp_const_false ) ;
} else {
SET_TOP ( mp_const_true ) ;
}
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_UNARY_OP :
2013-11-02 15:47:57 -04:00
unum = * ip + + ;
2013-12-10 12:27:24 -05:00
SET_TOP ( rt_unary_op ( unum , TOP ( ) ) ) ;
2013-11-02 15:47:57 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_BINARY_OP :
2013-10-15 17:25:17 -04:00
unum = * ip + + ;
obj2 = POP ( ) ;
2013-12-10 12:27:24 -05:00
obj1 = TOP ( ) ;
SET_TOP ( rt_binary_op ( unum , obj1 , obj2 ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_BUILD_TUPLE :
2013-10-16 11:12:52 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
sp - = unum - 1 ;
SET_TOP ( rt_build_tuple ( unum , sp ) ) ;
2013-10-16 11:12:52 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_BUILD_LIST :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
sp - = unum - 1 ;
SET_TOP ( rt_build_list ( unum , sp ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_LIST_APPEND :
2013-10-16 11:12:52 -04:00
DECODE_UINT ;
// I think it's guaranteed by the compiler that sp[unum] is a list
2014-01-18 09:10:48 -05:00
rt_list_append ( sp [ - unum ] , sp [ 0 ] ) ;
sp - - ;
2013-10-16 11:12:52 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_BUILD_MAP :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
PUSH ( rt_build_map ( unum ) ) ;
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_STORE_MAP :
2014-01-18 09:10:48 -05:00
sp - = 2 ;
rt_store_map ( sp [ 0 ] , sp [ 2 ] , sp [ 1 ] ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_MAP_ADD :
2013-10-16 15:54:01 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
// I think it's guaranteed by the compiler that sp[-unum - 1] is a map
rt_store_map ( sp [ - unum - 1 ] , sp [ 0 ] , sp [ - 1 ] ) ;
sp - = 2 ;
2013-10-16 15:54:01 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_BUILD_SET :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
sp - = unum - 1 ;
SET_TOP ( rt_build_set ( unum , sp ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_SET_ADD :
2013-10-16 15:57:49 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
// I think it's guaranteed by the compiler that sp[-unum] is a set
rt_store_set ( sp [ - unum ] , sp [ 0 ] ) ;
sp - - ;
2013-10-16 15:57:49 -04:00
break ;
2014-01-03 18:34:23 -05:00
# if MICROPY_ENABLE_SLICE
2014-01-02 19:48:56 -05:00
case MP_BC_BUILD_SLICE :
DECODE_UINT ;
if ( unum = = 2 ) {
obj2 = POP ( ) ;
obj1 = TOP ( ) ;
SET_TOP ( mp_obj_new_slice ( obj1 , obj2 , NULL ) ) ;
} else {
printf ( " 3-argument slice is not supported \n " ) ;
assert ( 0 ) ;
}
break ;
2014-01-03 18:34:23 -05:00
# endif
2014-01-02 19:48:56 -05:00
2013-12-21 13:17:45 -05:00
case MP_BC_UNPACK_SEQUENCE :
2013-11-26 10:15:50 -05:00
DECODE_UINT ;
2014-01-18 18:42:49 -05:00
rt_unpack_sequence ( sp [ 0 ] , unum , sp ) ;
2014-01-18 09:10:48 -05:00
sp + = unum - 1 ;
2013-11-26 10:15:50 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_MAKE_FUNCTION :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-02-01 08:05:04 -05:00
PUSH ( rt_make_function_from_id ( unum , MP_OBJ_NULL ) ) ;
break ;
case MP_BC_MAKE_FUNCTION_DEFARGS :
DECODE_UINT ;
SET_TOP ( rt_make_function_from_id ( unum , TOP ( ) ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_MAKE_CLOSURE :
2013-12-10 19:41:43 -05:00
DECODE_UINT ;
2014-01-29 13:58:52 -05:00
SET_TOP ( rt_make_closure_from_id ( unum , TOP ( ) ) ) ;
2013-12-10 19:41:43 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_CALL_FUNCTION :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
// unum & 0xff == n_positional
// (unum >> 8) & 0xff == n_keyword
sp - = ( unum & 0xff ) + ( ( unum > > 7 ) & 0x1fe ) ;
SET_TOP ( rt_call_function_n_kw ( * sp , unum & 0xff , ( unum > > 8 ) & 0xff , sp + 1 ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_CALL_METHOD :
2013-10-15 17:25:17 -04:00
DECODE_UINT ;
2014-01-18 09:10:48 -05:00
// unum & 0xff == n_positional
// (unum >> 8) & 0xff == n_keyword
sp - = ( unum & 0xff ) + ( ( unum > > 7 ) & 0x1fe ) + 1 ;
SET_TOP ( rt_call_method_n_kw ( unum & 0xff , ( unum > > 8 ) & 0xff , sp ) ) ;
2013-10-15 17:25:17 -04:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_RETURN_VALUE :
2014-01-31 17:55:05 -05:00
unwind_return :
while ( exc_sp > = exc_stack ) {
if ( exc_sp - > opcode = = MP_BC_SETUP_FINALLY ) {
// 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
// done (when END_FINALLY reached).
PUSH ( MP_OBJ_NEW_SMALL_INT ( UNWIND_RETURN ) ) ;
ip = exc_sp - > handler ;
// We don't need to do anything with sp, finally is just
// syntactic sugar for sequential execution??
// sp =
exc_sp - - ;
goto dispatch_loop ;
}
exc_sp - - ;
}
2013-10-15 17:25:17 -04:00
nlr_pop ( ) ;
2013-10-16 15:39:12 -04:00
* sp_in_out = sp ;
2014-03-22 07:49:31 -04:00
assert ( exc_sp = = exc_stack - 1 ) ;
2014-02-15 17:55:00 -05:00
return MP_VM_RETURN_NORMAL ;
2013-10-16 15:39:12 -04:00
2014-01-10 09:09:55 -05:00
case MP_BC_RAISE_VARARGS :
unum = * ip + + ;
2014-03-26 08:42:17 -04:00
assert ( unum < = 1 ) ;
if ( unum = = 0 ) {
// This assumes that nlr.ret_val holds last raised
// exception and is not overwritten since then.
obj1 = nlr . ret_val ;
} else {
obj1 = POP ( ) ;
}
2014-02-15 11:10:44 -05:00
nlr_jump ( rt_make_raise_obj ( obj1 ) ) ;
2014-01-10 09:09:55 -05:00
2013-12-21 13:17:45 -05:00
case MP_BC_YIELD_VALUE :
2013-10-16 15:39:12 -04:00
nlr_pop ( ) ;
* ip_in_out = ip ;
* sp_in_out = sp ;
2014-03-22 17:20:07 -04:00
* exc_sp_in_out = MP_TAGPTR_MAKE ( exc_sp , currently_in_except_block ) ;
2014-02-15 17:55:00 -05:00
return MP_VM_RETURN_YIELD ;
2013-10-15 17:25:17 -04:00
2013-12-21 13:17:45 -05:00
case MP_BC_IMPORT_NAME :
2013-12-10 12:27:24 -05:00
DECODE_QSTR ;
obj1 = POP ( ) ;
2014-01-19 06:48:48 -05:00
SET_TOP ( rt_import_name ( qst , obj1 , TOP ( ) ) ) ;
2013-12-10 12:27:24 -05:00
break ;
2013-12-21 13:17:45 -05:00
case MP_BC_IMPORT_FROM :
2013-12-10 12:27:24 -05:00
DECODE_QSTR ;
2014-01-19 06:48:48 -05:00
obj1 = rt_import_from ( TOP ( ) , qst ) ;
2013-12-10 12:27:24 -05:00
PUSH ( obj1 ) ;
break ;
2014-02-13 17:22:06 -05:00
case MP_BC_IMPORT_STAR :
2014-02-14 18:06:33 -05:00
rt_import_all ( POP ( ) ) ;
2014-02-13 17:22:06 -05:00
break ;
2013-10-15 17:25:17 -04:00
default :
2013-11-05 17:06:08 -05:00
printf ( " code %p, byte code 0x%02x not implemented \n " , ip , op ) ;
2013-10-15 17:25:17 -04:00
assert ( 0 ) ;
nlr_pop ( ) ;
2014-02-15 17:55:00 -05:00
return MP_VM_RETURN_NORMAL ;
2013-10-04 14:53:11 -04:00
}
2013-10-15 17:25:17 -04:00
}
} else {
// exception occurred
2014-03-26 14:37:06 -04:00
// check if it's a StopIteration within a for block
if ( * save_ip = = MP_BC_FOR_ITER & & mp_obj_is_subclass_fast ( mp_obj_get_type ( nlr . ret_val ) , & mp_type_StopIteration ) ) {
ip = save_ip + 1 ;
DECODE_ULABEL ; // the jump offset if iteration finishes; for labels are always forward
- - sp ; // pop the exhausted iterator
ip + = unum ; // jump to after for-block
goto outer_dispatch_loop ; // continue with dispatch loop
}
2014-01-18 18:24:36 -05:00
// set file and line number that the exception occurred at
2014-01-30 06:49:18 -05:00
// TODO: don't set traceback for exceptions re-raised by END_FINALLY.
// But consider how to handle nested exceptions.
2014-02-15 11:10:44 -05:00
if ( mp_obj_is_exception_instance ( nlr . ret_val ) ) {
2014-01-18 18:24:36 -05:00
machine_uint_t code_info_size = code_info [ 0 ] | ( code_info [ 1 ] < < 8 ) | ( code_info [ 2 ] < < 16 ) | ( code_info [ 3 ] < < 24 ) ;
2014-01-19 06:48:48 -05:00
qstr source_file = code_info [ 4 ] | ( code_info [ 5 ] < < 8 ) | ( code_info [ 6 ] < < 16 ) | ( code_info [ 7 ] < < 24 ) ;
qstr block_name = code_info [ 8 ] | ( code_info [ 9 ] < < 8 ) | ( code_info [ 10 ] < < 16 ) | ( code_info [ 11 ] < < 24 ) ;
2014-01-18 18:24:36 -05:00
machine_uint_t source_line = 1 ;
machine_uint_t bc = save_ip - code_info - code_info_size ;
2014-01-19 06:48:48 -05:00
//printf("find %lu %d %d\n", bc, code_info[12], code_info[13]);
2014-01-25 06:43:20 -05:00
for ( const byte * ci = code_info + 12 ; * ci & & bc > = ( ( * ci ) & 31 ) ; ci + + ) {
bc - = * ci & 31 ;
source_line + = * ci > > 5 ;
2014-01-18 18:24:36 -05:00
}
2014-01-19 07:38:49 -05:00
mp_obj_exception_add_traceback ( nlr . ret_val , source_file , source_line , block_name ) ;
2014-01-18 18:24:36 -05:00
}
2013-12-29 11:54:59 -05:00
while ( currently_in_except_block ) {
// nested exception
2014-03-22 07:49:31 -04:00
assert ( exc_sp > = exc_stack ) ;
2013-12-29 11:54:59 -05:00
// TODO make a proper message for nested exception
// at the moment we are just raising the very last exception (the one that caused the nested exception)
// move up to previous exception handler
2014-03-22 17:20:07 -04:00
currently_in_except_block = MP_TAGPTR_TAG ( exc_sp - > val_sp ) ; // restore previous state
2014-01-31 12:40:09 -05:00
exc_sp - - ; // pop back to previous exception handler
2013-12-29 11:54:59 -05:00
}
2014-03-22 07:49:31 -04:00
if ( exc_sp > = exc_stack ) {
2013-12-29 11:54:59 -05:00
// set flag to indicate that we are now handling an exception
currently_in_except_block = 1 ;
2013-10-15 17:25:17 -04:00
// catch exception and pass to byte code
2014-03-22 17:20:07 -04:00
sp = MP_TAGPTR_PTR ( exc_sp - > val_sp ) ;
2014-01-31 12:40:09 -05:00
ip = exc_sp - > handler ;
2013-10-15 18:46:01 -04:00
// push(traceback, exc-val, exc-type)
2013-12-21 13:17:45 -05:00
PUSH ( mp_const_none ) ;
2013-10-15 18:46:01 -04:00
PUSH ( nlr . ret_val ) ;
2013-12-29 12:17:43 -05:00
PUSH ( nlr . ret_val ) ; // TODO should be type(nlr.ret_val), I think...
2013-12-29 11:54:59 -05:00
2013-10-15 17:25:17 -04:00
} else {
2014-02-15 17:55:00 -05:00
// propagate exception to higher level
// TODO what to do about ip and sp? they don't really make sense at this point
fastn [ 0 ] = nlr . ret_val ; // must put exception here because sp is invalid
return MP_VM_RETURN_EXCEPTION ;
2013-10-15 17:25:17 -04:00
}
2013-10-04 14:53:11 -04:00
}
}
}