blueloveTH 2 years ago
parent
commit
429f572c53
3 changed files with 75 additions and 85 deletions
  1. 0 2
      docs/features/goto.md
  2. 2 2
      run_profile.sh
  3. 73 81
      src/vm.h

+ 0 - 2
docs/features/goto.md

@@ -7,8 +7,6 @@ pkpy supports `goto` and `label` just like C. You are allowed to change the cont
 
 ## Syntax
 
-Labels are named a dot `.` and an identifier.
-
 ```
 $goto <identifier>
 $label <identifier>

+ 2 - 2
run_profile.sh

@@ -1,5 +1,5 @@
-clang++ -pg -O2 -std=c++17 -fno-rtti -stdlib=libc++ -Wall -o pocketpy src/main.cpp
-time ./pocketpy benchmarks/primes.py
+clang++ -pg -O1 -std=c++17 -fno-rtti -stdlib=libc++ -Wall -o pocketpy src/main.cpp
+time ./pocketpy benchmarks/fib.py
 mv benchmarks/gmon.out .
 gprof pocketpy gmon.out > gprof.txt
 rm gmon.out

+ 73 - 81
src/vm.h

@@ -568,7 +568,6 @@ public:
     PyObject* new_module(StrName name);
     Str disassemble(CodeObject_ co);
     void init_builtin_types();
-    PyObject* _py_call(PyObject** sp_base, PyObject* callable, ArgsView args, ArgsView kwargs);
     PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true);
     PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false);
     void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
@@ -1110,12 +1109,81 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
     ArgsView kwargs(p1, s_data._sp);
 
     if(is_non_tagged_type(callable, tp_function)){
-        // ret is nullptr or a generator
-        PyObject* ret = _py_call(p0, callable, args, kwargs);
-        // stack resetting is handled by _py_call
-        if(ret != nullptr) return ret;
+        /*****************_py_call*****************/
+        // callable must be a `function` object
+        if(s_data.is_overflow()) StackOverflowError();
+
+        const Function& fn = CAST(Function&, callable);
+        const CodeObject* co = fn.decl->code.get();
+        int co_nlocals = co->varnames.size();
+
+        if(args.size() < fn.argc){
+            vm->TypeError(fmt(
+                "expected ",
+                fn.argc,
+                " positional arguments, but got ",
+                args.size(),
+                " (", fn.decl->code->name, ')'
+            ));
+        }
+
+        // if this function is simple, a.k.a, no kwargs and no *args and not a generator
+        // we can use a fast path to avoid using buffer copy
+        if(fn.is_simple){
+            if(args.size() > fn.argc) TypeError("too many positional arguments");
+            int spaces = co_nlocals - fn.argc;
+            for(int j=0; j<spaces; j++) PUSH(PY_NULL);
+            callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
+            if(op_call) return PY_OP_CALL;
+            return _run_top_frame();
+        }
+
+        int i = 0;
+        static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
+
+        // prepare args
+        for(int index: fn.decl->args) buffer[index] = args[i++];
+        // set extra varnames to nullptr
+        for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL;
+        // prepare kwdefaults
+        for(auto& kv: fn.decl->kwargs) buffer[kv.key] = kv.value;
+        
+        // handle *args
+        if(fn.decl->starred_arg != -1){
+            ArgsView vargs(args.begin() + i, args.end());
+            buffer[fn.decl->starred_arg] = VAR(vargs.to_tuple());
+            i += vargs.size();
+        }else{
+            // kwdefaults override
+            for(auto& kv: fn.decl->kwargs){
+                if(i >= args.size()) break;
+                buffer[kv.key] = args[i++];
+            }
+            if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')'));
+        }
+        
+        for(int i=0; i<kwargs.size(); i+=2){
+            StrName key = CAST(int, kwargs[i]);
+            int index = co->varnames_inv.try_get(key);
+            if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
+            buffer[index] = kwargs[i+1];
+        }
+        
+        if(co->is_generator){
+            s_data.reset(p0);
+            return _py_generator(
+                Frame(&s_data, nullptr, co, fn._module, callable),
+                ArgsView(buffer, buffer + co_nlocals)
+            );
+        }
+
+        // copy buffer back to stack
+        s_data.reset(args.begin());
+        for(int i=0; i<co_nlocals; i++) PUSH(buffer[i]);
+        callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
         if(op_call) return PY_OP_CALL;
         return _run_top_frame();
+        /*****************_py_call*****************/
     }
 
     if(is_non_tagged_type(callable, tp_type)){
@@ -1172,82 +1240,6 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
     return nullptr;
 }
 
-inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args, ArgsView kwargs){
-    // callable must be a `function` object
-    if(s_data.is_overflow()) StackOverflowError();
-
-    const Function& fn = CAST(Function&, callable);
-    const CodeObject* co = fn.decl->code.get();
-    int co_nlocals = co->varnames.size();
-
-    if(args.size() < fn.argc){
-        vm->TypeError(fmt(
-            "expected ",
-            fn.argc,
-            " positional arguments, but got ",
-            args.size(),
-            " (", fn.decl->code->name, ')'
-        ));
-    }
-
-    // if this function is simple, a.k.a, no kwargs and no *args and not a generator
-    // we can use a fast path to avoid using buffer copy
-    if(fn.is_simple){
-        if(args.size() > fn.argc) TypeError("too many positional arguments");
-        int spaces = co_nlocals - fn.argc;
-        for(int j=0; j<spaces; j++) PUSH(PY_NULL);
-        callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
-        return nullptr;
-    }
-
-    int i = 0;
-    static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
-
-    // prepare args
-    for(int index: fn.decl->args) buffer[index] = args[i++];
-    // set extra varnames to nullptr
-    for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL;
-
-    // prepare kwdefaults
-    for(auto& kv: fn.decl->kwargs) buffer[kv.key] = kv.value;
-    
-    // handle *args
-    if(fn.decl->starred_arg != -1){
-        ArgsView vargs(args.begin() + i, args.end());
-        buffer[fn.decl->starred_arg] = VAR(vargs.to_tuple());
-        i += vargs.size();
-    }else{
-        // kwdefaults override
-        for(auto& kv: fn.decl->kwargs){
-            if(i >= args.size()) break;
-            buffer[kv.key] = args[i++];
-        }
-        if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')'));
-    }
-    
-    for(int i=0; i<kwargs.size(); i+=2){
-        StrName key = CAST(int, kwargs[i]);
-        int index = co->varnames_inv.try_get(key);
-        if(index<0) TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
-        buffer[index] = kwargs[i+1];
-    }
-    
-    
-    if(co->is_generator){
-        s_data.reset(p0);
-        return _py_generator(
-            Frame(&s_data, nullptr, co, fn._module, callable),
-            ArgsView(buffer, buffer + co_nlocals)
-        );
-    }
-
-    // copy buffer back to stack
-    s_data.reset(args.begin());
-    for(int i=0; i<co_nlocals; i++) PUSH(buffer[i]);
-    callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
-    return nullptr;
-}
-
 DEF_SNAME(__get__);
 DEF_SNAME(__set__);