blueloveTH 1 gadu atpakaļ
vecāks
revīzija
9a1a7f92b7
6 mainītis faili ar 139 papildinājumiem un 116 dzēšanām
  1. 10 3
      include/pocketpy/error.h
  2. 9 9
      include/pocketpy/frame.h
  3. 1 0
      include/pocketpy/vm.h
  4. 107 93
      src/ceval.cpp
  5. 5 7
      src/frame.cpp
  6. 7 4
      src/vm.cpp

+ 10 - 3
include/pocketpy/error.h

@@ -11,9 +11,16 @@ struct NeedMoreLines {
     bool is_compiling_class;
 };
 
-struct HandledException {};
-struct UnhandledException {};
-struct ToBeRaisedException {};
+enum class InternalExceptionType: int{
+    Null, Handled, Unhandled, ToBeRaised
+};
+
+struct InternalException final{
+    InternalExceptionType type;
+    int arg;
+    InternalException(): type(InternalExceptionType::Null), arg(-1) {}
+    InternalException(InternalExceptionType type, int arg=-1): type(type), arg(arg) {}
+};
 
 enum CompileMode {
     EXEC_MODE,

+ 9 - 9
include/pocketpy/frame.h

@@ -70,7 +70,6 @@ struct ValueStack {
 
 struct Frame {
     int _ip;
-    int _next_ip;
     // This is for unwinding only, use `actual_sp_base()` for value stack access
     PyVar* _sp_base;
 
@@ -84,28 +83,29 @@ struct Frame {
 
     // function scope
     Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, PyVar* _locals_base)
-            : _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base) { }
+            : _ip(-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base) { }
 
     // exec/eval
     Frame(PyVar* p0, const CodeObject* co, PyVar _module, PyVar _callable, FastLocals _locals)
-            : _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
+            : _ip(-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
 
     // global scope
     Frame(PyVar* p0, const CodeObject_& co, PyVar _module)
-            : _ip(-1), _next_ip(0), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
+            : _ip(-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
 
     PyVar* actual_sp_base() const { return _locals.a; }
 
     int stack_size(ValueStack* _s) const { return _s->_sp - actual_sp_base(); }
     ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
 
-    void jump_abs(int i){ _next_ip = i; }
-    bool jump_to_exception_handler(ValueStack*);
+    [[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
+    void prepare_jump_break(ValueStack*, int);
     int _exit_block(ValueStack*, int);
-    void jump_abs_break(ValueStack*, int);
 
-    void loop_break(ValueStack* s_data, const CodeObject*){
-        jump_abs_break(s_data, co->_get_block_codei(_ip).end);
+    [[nodiscard]] int prepare_loop_break(ValueStack* s_data){
+        int target = co->_get_block_codei(_ip).end;
+        prepare_jump_break(s_data, target);
+        return target;
     }
 
     int curr_lineno() const { return co->lines[_ip].lineno; }

+ 1 - 0
include/pocketpy/vm.h

@@ -157,6 +157,7 @@ public:
     std::map<std::string_view, CodeObject_> __cached_codes;
     std::map<std::string_view, PyVar> __cached_op_funcs;
     FuncDecl_ __dynamic_func_decl;
+    InternalException __internal_exception;
     PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES];
 
 #if PK_ENABLE_PROFILER

+ 107 - 93
src/ceval.cpp

@@ -81,22 +81,6 @@ bool VM::py_ge(PyVar _0, PyVar _1){
 
 #undef BINARY_F_COMPARE
 
-PyVar VM::__run_top_frame(){
-    Frame* frame = &callstack.top();
-    const Frame* base_frame = frame;
-    bool need_raise = false;
-
-    while(true){
-        try{
-            if(need_raise){ need_raise = false; __raise_exc(); }
-/**********************************************************************/
-/* NOTE: 
- * Be aware of accidental gc!
- * DO NOT leave any strong reference of PyVar in the C stack
- */
-{
-
-
 #if PK_ENABLE_PROFILER
 #define CEVAL_STEP_CALLBACK()                                           \
     if(_ceval_on_step) _ceval_on_step(this, frame, byte);               \
@@ -109,17 +93,38 @@ PyVar VM::__run_top_frame(){
     }
 #endif
 
-#define DISPATCH() goto __NEXT_STEP;
+#define DISPATCH() { frame->_ip++; goto __NEXT_STEP; }
+#define DISPATCH_JUMP(__target) { frame->_ip = __target; goto __NEXT_STEP; }
+#define RETURN_OP_YIELD() { frame->_ip++; return PY_OP_YIELD; }
+
+PyVar VM::__run_top_frame(){
+    Frame* frame = &callstack.top();
+    const Frame* base_frame = frame;
 
+    while(true){
+        try{
+/**********************************************************************/
+{
 __NEXT_FRAME:
-    const CodeObject* co = frame->co;
+    if(__internal_exception.type == InternalExceptionType::Null){
+        // None
+        frame->_ip++;
+    }else if(__internal_exception.type == InternalExceptionType::Handled){
+        // HandledException + continue
+        frame->_ip = __internal_exception.arg;
+        __internal_exception = {};
+    }else{
+        // UnhandledException + continue (need_raise = true)
+        // ToBeRaisedException + continue (need_raise = true)
+        __internal_exception = {};
+        __raise_exc();      // no return
+    }
+
     // TODO: when jit is enabled, co_codes may not be const
-    const Bytecode* co_codes = co->codes.data();
+    const Bytecode* co_codes = frame->co->codes.data();
     Bytecode byte;
 
 __NEXT_STEP:
-    frame->_ip = frame->_next_ip;
-    frame->_next_ip++;
     byte = co_codes[frame->_ip];
     CEVAL_STEP_CALLBACK()
 
@@ -139,13 +144,13 @@ __NEXT_STEP:
         SECOND() = THIRD();
         THIRD() = _0;
     } DISPATCH()
-    case OP_PRINT_EXPR:{
+    case OP_PRINT_EXPR:
         if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
         POP();
-    } DISPATCH()
+        DISPATCH()
     /*****************************************/
     case OP_LOAD_CONST:
-        PUSH(co->consts[byte.arg]);
+        PUSH(frame->co->consts[byte.arg]);
         DISPATCH()
     case OP_LOAD_NONE:       PUSH(None); DISPATCH()
     case OP_LOAD_TRUE:       PUSH(True); DISPATCH()
@@ -155,7 +160,7 @@ __NEXT_STEP:
     /*****************************************/
     case OP_LOAD_ELLIPSIS:   PUSH(Ellipsis); DISPATCH()
     case OP_LOAD_FUNCTION: {
-        const FuncDecl_& decl = co->func_decls[byte.arg];
+        const FuncDecl_& decl = frame->co->func_decls[byte.arg];
         PyVar obj;
         if(decl->nested){
             NameDict_ captured = frame->_locals.to_namedict();
@@ -170,7 +175,7 @@ __NEXT_STEP:
     /*****************************************/
     case OP_LOAD_FAST: {
         PyVar _0 = frame->_locals[byte.arg];
-        if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
         PUSH(_0);
     } DISPATCH()
     case OP_LOAD_NAME: {
@@ -239,7 +244,7 @@ __NEXT_STEP:
     } DISPATCH()
     case OP_LOAD_SUBSCR_FAST:{
         PyVar _1 = frame->_locals[byte.arg];
-        if(_1 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        if(_1 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
         PyVar _0 = TOP();     // a
         auto _ti = _tp_info(_0);
         if(_ti->m__getitem__){
@@ -303,7 +308,7 @@ __NEXT_STEP:
     }DISPATCH()
     case OP_STORE_SUBSCR_FAST:{
         PyVar _2 = frame->_locals[byte.arg];    // b
-        if(_2 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        if(_2 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
         PyVar _1 = POPX();        // a
         PyVar _0 = POPX();        // val
         auto _ti = _tp_info(_1);
@@ -315,7 +320,7 @@ __NEXT_STEP:
     }DISPATCH()
     case OP_DELETE_FAST:{
         PyVar _0 = frame->_locals[byte.arg];
-        if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
         frame->_locals[byte.arg] = PY_NULL;
     }DISPATCH()
     case OP_DELETE_NAME:{
@@ -626,49 +631,45 @@ __NEXT_STEP:
     } DISPATCH()
     /*****************************************/
     case OP_JUMP_ABSOLUTE:
-        frame->jump_abs(byte.arg);
-        DISPATCH()
+        DISPATCH_JUMP(byte.arg)
     case OP_JUMP_ABSOLUTE_TOP:
-        frame->jump_abs(_CAST(int, POPX()));
+        DISPATCH_JUMP(_CAST(int, POPX()))
+    case OP_POP_JUMP_IF_FALSE:
+        if(!py_bool(POPX())) DISPATCH_JUMP(byte.arg)
         DISPATCH()
-    case OP_POP_JUMP_IF_FALSE:{
-        if(!py_bool(TOP())) frame->jump_abs(byte.arg);
-        POP();
-    } DISPATCH()
-    case OP_POP_JUMP_IF_TRUE:{
-        if(py_bool(TOP())) frame->jump_abs(byte.arg);
-        POP();
-    } DISPATCH()
-    case OP_JUMP_IF_TRUE_OR_POP:{
-        if(py_bool(TOP())) frame->jump_abs(byte.arg);
-        else POP();
-    } DISPATCH()
-    case OP_JUMP_IF_FALSE_OR_POP:{
-        if(!py_bool(TOP())) frame->jump_abs(byte.arg);
-        else POP();
-    } DISPATCH()
-    case OP_SHORTCUT_IF_FALSE_OR_POP:{
+    case OP_POP_JUMP_IF_TRUE:
+        if(py_bool(POPX())) DISPATCH_JUMP(byte.arg)
+        DISPATCH()
+    case OP_JUMP_IF_TRUE_OR_POP:
+        if(py_bool(POPX())) DISPATCH_JUMP(byte.arg)
+        DISPATCH()
+    case OP_JUMP_IF_FALSE_OR_POP:
+        if(!py_bool(POPX())) DISPATCH_JUMP(byte.arg)
+        DISPATCH()
+    case OP_SHORTCUT_IF_FALSE_OR_POP:
         if(!py_bool(TOP())){                // [b, False]
             STACK_SHRINK(2);                // []
             PUSH(vm->False);                // [False]
-            frame->jump_abs(byte.arg);
-        } else POP();                       // [b]
-    } DISPATCH()
+            DISPATCH_JUMP(byte.arg)
+        } else{
+            POP();                          // [b]
+            DISPATCH()
+        }
     case OP_LOOP_CONTINUE:
-        frame->jump_abs(byte.arg);
-        DISPATCH()
+        DISPATCH_JUMP(byte.arg)
     case OP_LOOP_BREAK:
-        frame->jump_abs_break(&s_data, byte.arg);
-        DISPATCH()
+        frame->prepare_jump_break(&s_data, byte.arg);
+        DISPATCH_JUMP(byte.arg)
     case OP_GOTO: {
         StrName _name(byte.arg);
-        int index = co->labels.try_get_likely_found(_name);
-        if(index < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
-        frame->jump_abs_break(&s_data, index);
-    } DISPATCH()
+        int target = frame->co->labels.try_get_likely_found(_name);
+        if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
+        frame->prepare_jump_break(&s_data, target);
+        DISPATCH_JUMP(target)
+    }
     /*****************************************/
     case OP_FSTRING_EVAL:{
-        PyVar _0 = co->consts[byte.arg];
+        PyVar _0 = frame->co->consts[byte.arg];
         std::string_view string = CAST(Str&, _0).sv();
         auto it = __cached_codes.find(string);
         CodeObject_ code;
@@ -743,8 +744,7 @@ __NEXT_STEP:
             goto __NEXT_FRAME;
         }
     } DISPATCH()
-    case OP_YIELD_VALUE:
-        return PY_OP_YIELD;
+    case OP_YIELD_VALUE: RETURN_OP_YIELD()
     /*****************************************/
     case OP_LIST_APPEND:{
         PyVar _0 = POPX();
@@ -785,34 +785,44 @@ __NEXT_STEP:
         DISPATCH()
     case OP_FOR_ITER:{
         PyVar _0 = py_next(TOP());
-        if(_0 == StopIteration) frame->loop_break(&s_data, co);
-        else PUSH(_0);
-    } DISPATCH()
+        if(_0 == StopIteration){
+            int target = frame->prepare_loop_break(&s_data);
+            DISPATCH_JUMP(target)
+        } else{
+            PUSH(_0);
+            DISPATCH()
+        }
+    } 
     case OP_FOR_ITER_STORE_FAST:{
         PyVar _0 = py_next(TOP());
         if(_0 == StopIteration){
-            frame->loop_break(&s_data, co);
+            int target = frame->prepare_loop_break(&s_data);
+            DISPATCH_JUMP(target)
         }else{
             frame->_locals[byte.arg] = _0;
+            DISPATCH()
         }
-    } DISPATCH()
+    }
     case OP_FOR_ITER_STORE_GLOBAL:{
         PyVar _0 = py_next(TOP());
         if(_0 == StopIteration){
-            frame->loop_break(&s_data, co);
+            int target = frame->prepare_loop_break(&s_data);
+            DISPATCH_JUMP(target)
         }else{
             frame->f_globals().set(StrName(byte.arg), _0);
+            DISPATCH()
         }
-    } DISPATCH()
+    }
     case OP_FOR_ITER_YIELD_VALUE:{
         PyVar _0 = py_next(TOP());
         if(_0 == StopIteration){
-            frame->loop_break(&s_data, co);
+            int target = frame->prepare_loop_break(&s_data);
+            DISPATCH_JUMP(target)
         }else{
             PUSH(_0);
-            return PY_OP_YIELD;
+            RETURN_OP_YIELD()
         }
-    } DISPATCH()
+    }
     case OP_FOR_ITER_UNPACK:{
         PyVar _0 = TOP();
         const PyTypeInfo* _ti = _tp_info(_0);
@@ -820,7 +830,8 @@ __NEXT_STEP:
             unsigned n = _ti->m__next__(this, _0);
             if(n == 0){
                 // StopIteration
-                frame->loop_break(&s_data, co);
+                int target = frame->prepare_loop_break(&s_data);
+                DISPATCH_JUMP(target)
             }else if(n == 1){
                 // UNPACK_SEQUENCE
                 __op_unpack_sequence(byte.arg);
@@ -837,13 +848,14 @@ __NEXT_STEP:
                 // UNPACK_SEQUENCE
                 __op_unpack_sequence(byte.arg);
             }else{
-                frame->loop_break(&s_data, co);
+                int target = frame->prepare_loop_break(&s_data);
+                DISPATCH_JUMP(target)
             }
         }
     } DISPATCH()
     /*****************************************/
     case OP_IMPORT_PATH:{
-        PyVar _0 = co->consts[byte.arg];
+        PyVar _0 = frame->co->consts[byte.arg];
         PUSH(py_import(CAST(Str&, _0)));
     } DISPATCH()
     case OP_POP_IMPORT_STAR: {
@@ -970,18 +982,18 @@ __NEXT_STEP:
     /*****************************************/
     case OP_FORMAT_STRING: {
         PyVar _0 = POPX();
-        const Str& spec = CAST(Str&, co->consts[byte.arg]);
+        const Str& spec = CAST(Str&, frame->co->consts[byte.arg]);
         PUSH(__format_object(_0, spec));
     } DISPATCH()
     /*****************************************/
     case OP_INC_FAST:{
         PyVar* p = &frame->_locals[byte.arg];
-        if(*p == PY_NULL) vm->NameError(co->varnames[byte.arg]);
+        if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
         *p = VAR(CAST(i64, *p) + 1);
     } DISPATCH()
     case OP_DEC_FAST:{
         PyVar* p = &frame->_locals[byte.arg];
-        if(*p == PY_NULL) vm->NameError(co->varnames[byte.arg]);
+        if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
         *p = VAR(CAST(i64, *p) - 1);
     } DISPATCH()
     case OP_INC_GLOBAL:{
@@ -1002,20 +1014,20 @@ __NEXT_STEP:
 }
 /**********************************************************************/
             PK_UNREACHABLE();
-        }catch(HandledException){
-            continue;
-        }catch(UnhandledException){
-            PyVar e_obj = POPX();
-            Exception& _e = PK_OBJ_GET(Exception, e_obj);
-            bool is_base_frame_to_be_popped = frame == base_frame;
-            __pop_frame();
-            if(callstack.empty()) throw _e;   // propagate to the top level
-            frame = &callstack.top();
-            PUSH(e_obj);
-            if(is_base_frame_to_be_popped) throw ToBeRaisedException();
-            need_raise = true;
-        }catch(ToBeRaisedException){
-            need_raise = true;
+        }catch(InternalException internal){
+            this->__internal_exception = internal;
+            if(internal.type == InternalExceptionType::Unhandled){
+                PyVar e_obj = POPX();
+                Exception& _e = PK_OBJ_GET(Exception, e_obj);
+                bool is_base_frame_to_be_popped = frame == base_frame;
+                __pop_frame();
+                if(callstack.empty()) throw _e;   // propagate to the top level
+                frame = &callstack.top();
+                PUSH(e_obj);
+                if(is_base_frame_to_be_popped){
+                    throw InternalException(InternalExceptionType::ToBeRaised);
+                }
+            }
         }
     }
 }
@@ -1030,6 +1042,8 @@ __NEXT_STEP:
 #undef STACK_VIEW
 
 #undef DISPATCH
+#undef DISPATCH_JUMP
+#undef RETURN_OP_YIELD
 #undef CEVAL_STEP_CALLBACK
 
 } // namespace pkpy

+ 5 - 7
src/frame.cpp

@@ -23,22 +23,21 @@ namespace pkpy{
         return fn._closure->try_get(name);
     }
 
-    bool Frame::jump_to_exception_handler(ValueStack* _s){
+    int Frame::prepare_jump_exception_handler(ValueStack* _s){
         // try to find a parent try block
         int block = co->iblocks[_ip];
         while(block >= 0){
             if(co->blocks[block].type == CodeBlockType::TRY_EXCEPT) break;
             block = co->blocks[block].parent;
         }
-        if(block < 0) return false;
+        if(block < 0) return -1;
         PyVar obj = _s->popx();         // pop exception object
         // get the stack size of the try block
         int _stack_size = co->blocks[block].base_stack_size;
         if(stack_size(_s) < _stack_size) throw std::runtime_error(_S("invalid state: ", stack_size(_s), '<', _stack_size).str());
         _s->reset(actual_sp_base() + _locals.size() + _stack_size);          // rollback the stack   
         _s->push(obj);                                      // push exception object
-        _next_ip = co->blocks[block].end;
-        return true;
+        return co->blocks[block].end;
     }
 
     int Frame::_exit_block(ValueStack* _s, int i){
@@ -47,10 +46,9 @@ namespace pkpy{
         return co->blocks[i].parent;
     }
 
-    void Frame::jump_abs_break(ValueStack* _s, int target){
+    void Frame::prepare_jump_break(ValueStack* _s, int target){
         int i = co->iblocks[_ip];
-        _next_ip = target;
-        if(_next_ip >= co->codes.size()){
+        if(target >= co->codes.size()){
             while(i>=0) i = _exit_block(_s, i);
         }else{
             // BUG (solved)

+ 7 - 4
src/vm.cpp

@@ -425,7 +425,7 @@ bool VM::__py_bool_non_trivial(PyVar obj){
     PyVar len_f = get_unbound_method(obj, __len__, &self, false);
     if(self != PY_NULL){
         PyVar ret = call_method(self, len_f);
-        return CAST(i64, ret) > 0;
+        return CAST(i64, ret) != 0;
     }
     return true;
 }
@@ -1398,7 +1398,7 @@ void VM::__raise_exc(bool re_raise){
         e._ip_on_error = frame->_ip;
         e._code_on_error = (void*)frame->co;
     }
-    bool ok = frame->jump_to_exception_handler(&s_data);
+    int next_ip = frame->prepare_jump_exception_handler(&s_data);
 
     int actual_ip = frame->_ip;
     if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error;
@@ -1407,8 +1407,11 @@ void VM::__raise_exc(bool re_raise){
     if(frame->_callable == nullptr) current_f_name = "";    // not in a function
     e.st_push(frame->co->src, current_line, nullptr, current_f_name);
 
-    if(ok) throw HandledException();
-    else throw UnhandledException();
+    if(next_ip >= 0){
+        throw InternalException(InternalExceptionType::Handled, next_ip);
+    }else{
+        throw InternalException(InternalExceptionType::Unhandled);
+    }
 }
 
 void ManagedHeap::mark() {