blueloveTH 1 год назад
Родитель
Сommit
b703abbbb2
6 измененных файлов с 76 добавлено и 58 удалено
  1. 0 1
      include/pocketpy/common.h
  2. 3 17
      include/pocketpy/opcodes.h
  3. 45 29
      src/ceval.cpp
  4. 21 10
      src/expr.cpp
  5. 4 1
      src/vm.cpp
  6. 3 0
      tests/05_list.py

+ 0 - 1
include/pocketpy/common.h

@@ -125,7 +125,6 @@ struct Type {
 
 struct PyObject;
 #define PK_BITS(p) (reinterpret_cast<i64>(p))
-#define PK_SMALL_INT(val) (reinterpret_cast<PyObject*>(val << 2 | 0b10))
 
 // is_pod<> for c++17 and c++20
 template<typename T>

+ 3 - 17
include/pocketpy/opcodes.h

@@ -14,23 +14,7 @@ OPCODE(LOAD_NONE)
 OPCODE(LOAD_TRUE)
 OPCODE(LOAD_FALSE)
 /**************************/
-OPCODE(LOAD_INT_0)
-OPCODE(LOAD_INT_1)
-OPCODE(LOAD_INT_2)
-OPCODE(LOAD_INT_3)
-OPCODE(LOAD_INT_4)
-OPCODE(LOAD_INT_5)
-OPCODE(LOAD_INT_6)
-OPCODE(LOAD_INT_7)
-OPCODE(LOAD_INT_8)
-OPCODE(LOAD_INT_9)
-OPCODE(LOAD_INT_10)
-OPCODE(LOAD_INT_11)
-OPCODE(LOAD_INT_12)
-OPCODE(LOAD_INT_13)
-OPCODE(LOAD_INT_14)
-OPCODE(LOAD_INT_15)
-OPCODE(LOAD_INT_16)
+OPCODE(LOAD_SMALL_INT)
 /**************************/
 OPCODE(LOAD_ELLIPSIS)
 OPCODE(LOAD_FUNCTION)
@@ -44,12 +28,14 @@ OPCODE(LOAD_ATTR)
 OPCODE(LOAD_CLASS_GLOBAL)
 OPCODE(LOAD_METHOD)
 OPCODE(LOAD_SUBSCR)
+OPCODE(LOAD_SUBSCR_FAST)
 
 OPCODE(STORE_FAST)
 OPCODE(STORE_NAME)
 OPCODE(STORE_GLOBAL)
 OPCODE(STORE_ATTR)
 OPCODE(STORE_SUBSCR)
+OPCODE(STORE_SUBSCR_FAST)
 
 OPCODE(DELETE_FAST)
 OPCODE(DELETE_NAME)

+ 45 - 29
src/ceval.cpp

@@ -10,7 +10,7 @@ namespace pkpy{
 
 #define PREDICT_INT_DIV_OP(op)  \
     if(is_small_int(_0) && is_small_int(_1)){   \
-        if(_1 == PK_SMALL_INT(0)) ZeroDivisionError();   \
+        if(_1 == (PyObject*)0b10) ZeroDivisionError();   \
         TOP() = VAR((PK_BITS(_0)>>2) op (PK_BITS(_1)>>2)); \
         DISPATCH() \
     }
@@ -112,30 +112,13 @@ __NEXT_STEP:;
     } DISPATCH();
     /*****************************************/
     TARGET(LOAD_CONST)
-        if(heap._should_auto_collect()) heap._auto_collect();
         PUSH(co->consts[byte.arg]);
         DISPATCH();
     TARGET(LOAD_NONE)       PUSH(None); DISPATCH();
     TARGET(LOAD_TRUE)       PUSH(True); DISPATCH();
     TARGET(LOAD_FALSE)      PUSH(False); DISPATCH();
     /*****************************************/
-    TARGET(LOAD_INT_0)      PUSH(PK_SMALL_INT(0)); DISPATCH();
-    TARGET(LOAD_INT_1)      PUSH(PK_SMALL_INT(1)); DISPATCH();
-    TARGET(LOAD_INT_2)      PUSH(PK_SMALL_INT(2)); DISPATCH();
-    TARGET(LOAD_INT_3)      PUSH(PK_SMALL_INT(3)); DISPATCH();
-    TARGET(LOAD_INT_4)      PUSH(PK_SMALL_INT(4)); DISPATCH();
-    TARGET(LOAD_INT_5)      PUSH(PK_SMALL_INT(5)); DISPATCH();
-    TARGET(LOAD_INT_6)      PUSH(PK_SMALL_INT(6)); DISPATCH();
-    TARGET(LOAD_INT_7)      PUSH(PK_SMALL_INT(7)); DISPATCH();
-    TARGET(LOAD_INT_8)      PUSH(PK_SMALL_INT(8)); DISPATCH();
-    TARGET(LOAD_INT_9)      PUSH(PK_SMALL_INT(9)); DISPATCH();
-    TARGET(LOAD_INT_10)     PUSH(PK_SMALL_INT(10)); DISPATCH();
-    TARGET(LOAD_INT_11)     PUSH(PK_SMALL_INT(11)); DISPATCH();
-    TARGET(LOAD_INT_12)     PUSH(PK_SMALL_INT(12)); DISPATCH();
-    TARGET(LOAD_INT_13)     PUSH(PK_SMALL_INT(13)); DISPATCH();
-    TARGET(LOAD_INT_14)     PUSH(PK_SMALL_INT(14)); DISPATCH();
-    TARGET(LOAD_INT_15)     PUSH(PK_SMALL_INT(15)); DISPATCH();
-    TARGET(LOAD_INT_16)     PUSH(PK_SMALL_INT(16)); DISPATCH();
+    TARGET(LOAD_SMALL_INT)  PUSH((PyObject*)(uintptr_t)byte.arg); DISPATCH();
     /*****************************************/
     TARGET(LOAD_ELLIPSIS)   PUSH(Ellipsis); DISPATCH();
     TARGET(LOAD_FUNCTION) {
@@ -153,7 +136,6 @@ __NEXT_STEP:;
     TARGET(LOAD_NULL) PUSH(PY_NULL); DISPATCH();
     /*****************************************/
     TARGET(LOAD_FAST) {
-        if(heap._should_auto_collect()) heap._auto_collect();
         PyObject* _0 = frame->_locals[byte.arg];
         if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
         PUSH(_0);
@@ -175,7 +157,6 @@ __NEXT_STEP:;
         vm->NameError(_name);
     } DISPATCH();
     TARGET(LOAD_NONLOCAL) {
-        if(heap._should_auto_collect()) heap._auto_collect();
         StrName _name(byte.arg);
         PyObject* _0 = frame->f_closure_try_get(_name);
         if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
@@ -186,7 +167,6 @@ __NEXT_STEP:;
         vm->NameError(_name);
     } DISPATCH();
     TARGET(LOAD_GLOBAL){
-        if(heap._should_auto_collect()) heap._auto_collect();
         StrName _name(byte.arg);
         PyObject* _0 = frame->f_globals().try_get_likely_found(_name);
         if(_0 != nullptr) { PUSH(_0); DISPATCH(); }
@@ -224,6 +204,17 @@ __NEXT_STEP:;
             TOP() = call_method(_0, __getitem__, _1);
         }
     } DISPATCH();
+    TARGET(LOAD_SUBSCR_FAST){
+        PyObject* _1 = frame->_locals[byte.arg];
+        if(_1 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        PyObject* _0 = TOP();     // a
+        auto _ti = _inst_type_info(_0);
+        if(_ti->m__getitem__){
+            TOP() = _ti->m__getitem__(this, _0, _1);
+        }else{
+            TOP() = call_method(_0, __getitem__, _1);
+        }
+    } DISPATCH();
     TARGET(STORE_FAST)
         frame->_locals[byte.arg] = POPX();
         DISPATCH();
@@ -258,6 +249,18 @@ __NEXT_STEP:;
             call_method(_1, __setitem__, _2, _0);
         }
     }DISPATCH();
+    TARGET(STORE_SUBSCR_FAST){
+        PyObject* _2 = frame->_locals[byte.arg];    // b
+        if(_2 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
+        PyObject* _1 = POPX();        // a
+        PyObject* _0 = POPX();        // val
+        auto _ti = _inst_type_info(_1);
+        if(_ti->m__setitem__){
+            _ti->m__setitem__(this, _1, _2, _0);
+        }else{
+            call_method(_1, __setitem__, _2, _0);
+        }
+    }DISPATCH();
     TARGET(DELETE_FAST){
         PyObject* _0 = frame->_locals[byte.arg];
         if(_0 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
@@ -620,6 +623,7 @@ __NEXT_STEP:;
         TOP() = py_repr(TOP());
         DISPATCH();
     TARGET(CALL){
+        if(heap._should_auto_collect()) heap._auto_collect();
         PyObject* _0 = vectorcall(
             byte.arg & 0xFF,          // ARGC
             (byte.arg>>8) & 0xFF,     // KWARGC
@@ -629,6 +633,7 @@ __NEXT_STEP:;
         PUSH(_0);
     } DISPATCH();
     TARGET(CALL_TP){
+        if(heap._should_auto_collect()) heap._auto_collect();
         PyObject* _0;
         PyObject* _1;
         PyObject* _2;
@@ -772,14 +777,25 @@ __NEXT_STEP:;
     } DISPATCH();
     /*****************************************/
     TARGET(UNPACK_SEQUENCE){
-        auto _lock = heap.gc_scope_lock();  // lock the gc via RAII!!
-        PyObject* _0 = py_iter(POPX());
-        for(int i=0; i<byte.arg; i++){
-            PyObject* _1 = py_next(_0);
-            if(_1 == StopIteration) ValueError("not enough values to unpack");
-            PUSH(_1);
+        PyObject* _0 = POPX();
+        if(is_type(_0, VM::tp_tuple)){
+            // fast path for tuple
+            Tuple& tuple = PK_OBJ_GET(Tuple, _0);
+            if(tuple.size() == byte.arg){
+                for(PyObject* obj: tuple) PUSH(obj);
+            }else{
+                ValueError(_S("expected ", (int)byte.arg, " values to unpack, got ", (int)tuple.size()));
+            }
+        }else{
+            auto _lock = heap.gc_scope_lock();  // lock the gc via RAII!!
+            _0 = py_iter(_0);
+            for(int i=0; i<byte.arg; i++){
+                PyObject* _1 = py_next(_0);
+                if(_1 == StopIteration) ValueError("not enough values to unpack");
+                PUSH(_1);
+            }
+            if(py_next(_0) != StopIteration) ValueError("too many values to unpack");
         }
-        if(py_next(_0) != StopIteration) ValueError("too many values to unpack");
     } DISPATCH();
     TARGET(UNPACK_EX) {
         auto _lock = heap.gc_scope_lock();  // lock the gc via RAII!!

+ 21 - 10
src/expr.cpp

@@ -86,9 +86,9 @@ namespace pkpy{
     }
 
     int CodeEmitContext::emit_int(i64 value, int line){
-        if(value >= 0 && value <= 16){
-            uint8_t op = OP_LOAD_INT_0 + (uint8_t)value;
-            return emit_((Opcode)op, BC_NOARG, line);
+        if(value >= 0 && value < 1024){
+            value = (value << 2) | 0b10;
+            return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line);
         }else{
             return emit_(OP_LOAD_CONST, add_const(VAR(value)), line);
         }
@@ -359,8 +359,7 @@ namespace pkpy{
             Bytecode& prev = ctx->co->codes.back();
             if(prev.op == OP_BUILD_TUPLE && prev.arg == items.size()){
                 // build tuple and unpack it is meaningless
-                prev.op = OP_NO_OP;
-                prev.arg = BC_NOARG;
+                ctx->revert_last_emit_();
             }else{
                 ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line);
             }
@@ -537,20 +536,32 @@ namespace pkpy{
     void SubscrExpr::emit_(CodeEmitContext* ctx){
         a->emit_(ctx);
         b->emit_(ctx);
-        ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
+        if(b->is_name() && ctx->co->codes.back().op == OP_LOAD_FAST){
+            auto arg = ctx->co->codes.back().arg;
+            ctx->revert_last_emit_();
+            ctx->emit_(OP_LOAD_SUBSCR_FAST, arg, line);
+        }else{
+            ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
+        }
     }
 
-    bool SubscrExpr::emit_del(CodeEmitContext* ctx){
+    bool SubscrExpr::emit_store(CodeEmitContext* ctx){
         a->emit_(ctx);
         b->emit_(ctx);
-        ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line);
+        if(b->is_name() && ctx->co->codes.back().op == OP_LOAD_FAST){
+            auto arg = ctx->co->codes.back().arg;
+            ctx->revert_last_emit_();
+            ctx->emit_(OP_STORE_SUBSCR_FAST, arg, line);
+        }else{
+            ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
+        }
         return true;
     }
 
-    bool SubscrExpr::emit_store(CodeEmitContext* ctx){
+    bool SubscrExpr::emit_del(CodeEmitContext* ctx){
         a->emit_(ctx);
         b->emit_(ctx);
-        ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
+        ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line);
         return true;
     }
 

+ 4 - 1
src/vm.cpp

@@ -577,12 +577,15 @@ static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
         case OP_DELETE_GLOBAL: case OP_INC_GLOBAL: case OP_DEC_GLOBAL: case OP_STORE_CLASS_ATTR: case OP_FOR_ITER_STORE_GLOBAL:
             argStr += _S(" (", StrName(byte.arg).sv(), ")").sv();
             break;
-        case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: case OP_INC_FAST: case OP_DEC_FAST: case OP_FOR_ITER_STORE_FAST:
+        case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: case OP_INC_FAST: case OP_DEC_FAST:
+        case OP_FOR_ITER_STORE_FAST: case OP_LOAD_SUBSCR_FAST: case OP_STORE_SUBSCR_FAST:
             argStr += _S(" (", co->varnames[byte.arg].sv(), ")").sv();
             break;
         case OP_LOAD_FUNCTION:
             argStr += _S(" (", co->func_decls[byte.arg]->code->name, ")").sv();
             break;
+        case OP_LOAD_SMALL_INT:
+            argStr += _S(" (", (int)(byte.arg >> 2), ")").sv();
     }
     return argStr;
 }

+ 3 - 0
tests/05_list.py

@@ -129,3 +129,6 @@ try:
     exit(1)
 except ValueError:
     pass
+
+a, b = [1, 2]
+assert a == 1 and b == 2