blueloveTH 2 anni fa
parent
commit
5c8fd54fd6
3 ha cambiato i file con 53 aggiunte e 31 eliminazioni
  1. 6 4
      src/frame.h
  2. 1 0
      src/obj.h
  3. 46 27
      src/vm.h

+ 6 - 4
src/frame.h

@@ -102,6 +102,7 @@ struct Frame {
     int _ip = -1;
     int _ip = -1;
     int _next_ip = 0;
     int _next_ip = 0;
     ValueStack* _s;
     ValueStack* _s;
+    // This is for unwinding only, use `actual_sp_base()` for value stack access
     PyObject** _sp_base;
     PyObject** _sp_base;
 
 
     const CodeObject* co;
     const CodeObject* co;
@@ -137,8 +138,9 @@ struct Frame {
         return co->src->snapshot(line);
         return co->src->snapshot(line);
     }
     }
 
 
-    int stack_size() const { return _s->_sp - _sp_base; }
-    ArgsView stack_view() const { return ArgsView(_sp_base, _s->_sp); }
+    PyObject** actual_sp_base() const { return _locals.a; }
+    int stack_size() const { return _s->_sp - actual_sp_base(); }
+    ArgsView stack_view() const { return ArgsView(actual_sp_base(), _s->_sp); }
 
 
     void jump_abs(int i){ _next_ip = i; }
     void jump_abs(int i){ _next_ip = i; }
     // void jump_rel(int i){ _next_ip += i; }
     // void jump_rel(int i){ _next_ip += i; }
@@ -155,8 +157,8 @@ struct Frame {
         // get the stack size of the try block (depth of for loops)
         // get the stack size of the try block (depth of for loops)
         int _stack_size = co->blocks[block].for_loop_depth;
         int _stack_size = co->blocks[block].for_loop_depth;
         if(stack_size() < _stack_size) throw std::runtime_error("invalid stack size");
         if(stack_size() < _stack_size) throw std::runtime_error("invalid stack size");
-        _s->reset(_sp_base + _stack_size);             // rollback the stack   
-        _s->push(obj);                      // push exception object
+        _s->reset(actual_sp_base() + _stack_size);          // rollback the stack   
+        _s->push(obj);                                      // push exception object
         _next_ip = co->blocks[block].end;
         _next_ip = co->blocks[block].end;
         return true;
         return true;
     }
     }

+ 1 - 0
src/obj.h

@@ -34,6 +34,7 @@ struct FuncDecl {
     pod_vector<KwArg> kwargs;   // indices in co->varnames
     pod_vector<KwArg> kwargs;   // indices in co->varnames
     bool nested = false;        // whether this function is nested
     bool nested = false;        // whether this function is nested
     void _gc_mark() const;
     void _gc_mark() const;
+    bool is_simple() const { return kwargs.empty() && starred_arg == -1; }
 };
 };
 
 
 using FuncDecl_ = shared_ptr<FuncDecl>;
 using FuncDecl_ = shared_ptr<FuncDecl>;

+ 46 - 27
src/vm.h

@@ -593,6 +593,33 @@ inline PyObject* VM::new_module(StrName name) {
     return obj;
     return obj;
 }
 }
 
 
+inline std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
+    std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
+    switch(byte.op){
+        case OP_LOAD_CONST:
+            if(vm != nullptr){
+                argStr += fmt(" (", CAST(Str, vm->asRepr(co->consts[byte.arg])), ")");
+            }
+            break;
+        case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL:
+        case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
+        case OP_IMPORT_NAME: case OP_BEGIN_CLASS:
+        case OP_DELETE_GLOBAL:
+            argStr += fmt(" (", StrName(byte.arg).sv(), ")");
+            break;
+        case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST:
+            argStr += fmt(" (", co->varnames[byte.arg].sv(), ")");
+            break;
+        case OP_BINARY_OP:
+            argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")");
+            break;
+        case OP_LOAD_FUNCTION:
+            argStr += fmt(" (", co->func_decls[byte.arg]->code->name, ")");
+            break;
+    }
+    return argStr;
+}
+
 inline Str VM::disassemble(CodeObject_ co){
 inline Str VM::disassemble(CodeObject_ co){
     auto pad = [](const Str& s, const int n){
     auto pad = [](const Str& s, const int n){
         if(s.length() >= n) return s.substr(0, n);
         if(s.length() >= n) return s.substr(0, n);
@@ -625,27 +652,7 @@ inline Str VM::disassemble(CodeObject_ co){
         ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
         ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
         ss << " " << pad(OP_NAMES[byte.op], 20) << " ";
         ss << " " << pad(OP_NAMES[byte.op], 20) << " ";
         // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
         // ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
-        std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
-        switch(byte.op){
-            case OP_LOAD_CONST:
-                argStr += fmt(" (", CAST(Str, asRepr(co->consts[byte.arg])), ")");
-                break;
-            case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL:
-            case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
-            case OP_IMPORT_NAME: case OP_BEGIN_CLASS:
-            case OP_DELETE_GLOBAL:
-                argStr += fmt(" (", StrName(byte.arg).sv(), ")");
-                break;
-            case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST:
-                argStr += fmt(" (", co->varnames[byte.arg].sv(), ")");
-                break;
-            case OP_BINARY_OP:
-                argStr += fmt(" (", BINARY_SPECIAL_METHODS[byte.arg], ")");
-                break;
-            case OP_LOAD_FUNCTION:
-                argStr += fmt(" (", co->func_decls[byte.arg]->code->name, ")");
-                break;
-        }
+        std::string argStr = _opcode_argstr(this, byte, co.get());
         ss << pad(argStr, 40);      // may overflow
         ss << pad(argStr, 40);      // may overflow
         ss << co->blocks[byte.block].type;
         ss << co->blocks[byte.block].type;
         if(i != co->codes.size() - 1) ss << '\n';
         if(i != co->codes.size() - 1) ss << '\n';
@@ -706,7 +713,7 @@ inline void VM::_log_s_data(const char* title) {
     }
     }
     output.push_back(']');
     output.push_back(']');
     Bytecode byte = frame->co->codes[frame->_ip];
     Bytecode byte = frame->co->codes[frame->_ip];
-    std::cout << output << " " << OP_NAMES[byte.op] << std::endl;
+    std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
 }
 }
 
 
 inline void VM::init_builtin_types(){
 inline void VM::init_builtin_types(){
@@ -868,11 +875,8 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
 
 
     const Function& fn = CAST(Function&, callable);
     const Function& fn = CAST(Function&, callable);
     const CodeObject* co = fn.decl->code.get();
     const CodeObject* co = fn.decl->code.get();
+    PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module;
 
 
-    static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
-    for(int i=0; i<co->varnames.size(); i++) buffer[i] = nullptr;
-
-    int i = 0;
     if(args.size() < fn.decl->args.size()){
     if(args.size() < fn.decl->args.size()){
         vm->TypeError(fmt(
         vm->TypeError(fmt(
             "expected ",
             "expected ",
@@ -883,6 +887,22 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
         ));
         ));
     }
     }
 
 
+    // if this function is simple, a.k.a, no kwargs or *args
+    // we can avoid using buffer copy
+    if(fn.decl->is_simple() && !co->is_generator){
+#if DEBUG_EXTRA_CHECK
+        for(PyObject** p=p0; p<args.begin(); p++) *p = nullptr;
+#endif
+        int spaces = co->varnames.size() - fn.decl->args.size();
+        for(int j=0; j<spaces; j++) PUSH(nullptr);
+        callstack.emplace(&s_data, p0, co, _module, callable, FastLocals(co, args.begin()));
+        return nullptr;
+    }
+
+    int i = 0;
+    static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
+    memset(buffer, 0, sizeof(void*) * co->varnames.size());
+
     // prepare args
     // prepare args
     for(int index: fn.decl->args) buffer[index] = args[i++];
     for(int index: fn.decl->args) buffer[index] = args[i++];
     // prepare kwdefaults
     // prepare kwdefaults
@@ -911,7 +931,6 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
         if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
         if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
         buffer[index] = kwargs[i+1];
         buffer[index] = kwargs[i+1];
     }
     }
-    PyObject* _module = fn._module != nullptr ? fn._module : top_frame()->_module;
     
     
     s_data.reset(p0);
     s_data.reset(p0);
     if(co->is_generator){
     if(co->is_generator){