blueloveTH hace 2 años
padre
commit
849c6aabb5
Se han modificado 7 ficheros con 27 adiciones y 17 borrados
  1. 1 0
      docs/features/basic.md
  2. 1 4
      docs/features/goto.md
  3. 10 0
      docs/features/ub.md
  4. 3 2
      src/ceval.h
  5. 3 2
      src/frame.h
  6. 1 0
      src/obj.h
  7. 8 9
      src/vm.h

+ 1 - 0
docs/features/basic.md

@@ -1,6 +1,7 @@
 ---
 icon: dot
 order: 100
+title: Basic Features
 ---
 
 # basic

+ 1 - 4
docs/features/goto.md

@@ -1,5 +1,6 @@
 ---
 icon: dot
+title: Goto Statement
 ---
 
 # goto/label
@@ -25,7 +26,3 @@ for i in range(10):
 
 label .exit
 ```
-
-!!!
-If we detect an illegal divert, you will get an `UnexpectedError` or the behaviour is undefined.
-!!!

+ 10 - 0
docs/features/ub.md

@@ -0,0 +1,10 @@
+---
+icon: dot
+title: Undefined Behaviour
+---
+
+These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined if you do the following things.
+
+1. Delete a builtin object. For example, `del int.__add__`.
+2. Call an unbound method with the wrong type of `self`. For example, `int.__add__('1', 2)`.
+3. Use goto statement to jump out of a context block.

+ 3 - 2
src/ceval.h

@@ -83,11 +83,12 @@ __NEXT_STEP:;
     TARGET(LOAD_FUNCTION) {
         FuncDecl_ decl = co->func_decls[byte.arg];
         bool is_simple = decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
+        int argc = decl->args.size();
         PyObject* obj;
         if(decl->nested){
-            obj = VAR(Function({decl, is_simple, frame->_module, frame->_locals.to_namedict()}));
+            obj = VAR(Function({decl, is_simple, argc, frame->_module, frame->_locals.to_namedict()}));
         }else{
-            obj = VAR(Function({decl, is_simple, frame->_module}));
+            obj = VAR(Function({decl, is_simple, argc, frame->_module}));
         }
         PUSH(obj);
     } DISPATCH();

+ 3 - 2
src/frame.h

@@ -63,8 +63,9 @@ struct ValueStackImpl {
     // We allocate extra MAX_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
     PyObject* _begin[MAX_SIZE + MAX_SIZE/128];
     PyObject** _sp;
+    PyObject** _max_end;
 
-    ValueStackImpl(): _sp(_begin) {}
+    ValueStackImpl(): _sp(_begin), _max_end(_begin + MAX_SIZE) {}
 
     PyObject*& top(){ return _sp[-1]; }
     PyObject* top() const { return _sp[-1]; }
@@ -90,7 +91,7 @@ struct ValueStackImpl {
         _sp = sp;
     }
     void clear() { _sp = _begin; }
-    bool is_overflow() const { return _sp >= _begin + MAX_SIZE; }
+    bool is_overflow() const { return _sp >= _max_end; }
     
     ValueStackImpl(const ValueStackImpl&) = delete;
     ValueStackImpl(ValueStackImpl&&) = delete;

+ 1 - 0
src/obj.h

@@ -47,6 +47,7 @@ using FuncDecl_ = shared_ptr<FuncDecl>;
 struct Function{
     FuncDecl_ decl;
     bool is_simple;
+    int argc;   // cached argc
     PyObject* _module;
     NameDict_ _closure;
 };

+ 8 - 9
src/vm.h

@@ -1001,12 +1001,11 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
 
     const Function& fn = CAST(Function&, callable);
     const CodeObject* co = fn.decl->code.get();
-    PyObject* _module = fn._module != nullptr ? fn._module : callstack.top()._module;
 
-    if(args.size() < fn.decl->args.size()){
+    if(args.size() < fn.argc){
         vm->TypeError(fmt(
             "expected ",
-            fn.decl->args.size(),
+            fn.argc,
             " positional arguments, but got ",
             args.size(),
             " (", fn.decl->code->name, ')'
@@ -1015,11 +1014,11 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
 
     // 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 && kwargs.size()==0){
-        if(args.size() > fn.decl->args.size()) TypeError("too many positional arguments");
-        int spaces = co->varnames.size() - fn.decl->args.size();
+    if(fn.is_simple){
+        if(args.size() > fn.argc) TypeError("too many positional arguments");
+        int spaces = co->varnames.size() - fn.argc;
         for(int j=0; j<spaces; j++) PUSH(nullptr);
-        callstack.emplace(&s_data, p0, co, _module, callable, FastLocals(co, args.begin()));
+        callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
         return nullptr;
     }
 
@@ -1062,7 +1061,7 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
     if(co->is_generator){
         PyObject* ret = PyIter(Generator(
             this,
-            Frame(&s_data, nullptr, co, _module, callable),
+            Frame(&s_data, nullptr, co, fn._module, callable),
             ArgsView(buffer, buffer + co->varnames.size())
         ));
         return ret;
@@ -1070,7 +1069,7 @@ inline PyObject* VM::_py_call(PyObject** p0, PyObject* callable, ArgsView args,
 
     // copy buffer to stack
     for(int i=0; i<co->varnames.size(); i++) PUSH(buffer[i]);
-    callstack.emplace(&s_data, p0, co, _module, callable);
+    callstack.emplace(&s_data, p0, co, fn._module, callable);
     return nullptr;
 }