mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
22e74a16a3
commit
3de3e625ee
@ -3,6 +3,8 @@
|
||||
|
||||
using namespace pkpy;
|
||||
|
||||
typedef int (*LuaStyleFuncC)(VM*);
|
||||
|
||||
struct LuaStack: public ValueStackImpl<32>{
|
||||
PyObject*& at(int i) {
|
||||
if(i < 0 || i >= size()){
|
||||
@ -177,12 +179,7 @@ void pkpy_vm_destroy(pkpy_vm* vm_handle) {
|
||||
}
|
||||
|
||||
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
LuaStyleFuncC f;
|
||||
if(args[-1] != PY_NULL){
|
||||
f = _py_cast<NativeFunc&>(vm, args[-1])._lua_f;
|
||||
} else {
|
||||
f = _py_cast<NativeFunc&>(vm, args[-2])._lua_f;
|
||||
}
|
||||
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
||||
CVM* cvm = (CVM*) vm;
|
||||
|
||||
//setup c stack
|
||||
@ -225,7 +222,7 @@ PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f, int argc) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
||||
nf._lua_f = (LuaStyleFuncC) f;
|
||||
nf.set_userdata(f);
|
||||
ERRHANDLER_OPEN
|
||||
vm->c_data->safe_push(py_var(vm, nf));
|
||||
ERRHANDLER_CLOSE
|
||||
|
@ -98,14 +98,13 @@ __NEXT_STEP:;
|
||||
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
||||
TARGET(LOAD_FUNCTION) {
|
||||
FuncDecl_ decl = co->func_decls[byte.arg];
|
||||
bool is_simple = decl->starred_kwarg==-1 && decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
||||
PyObject* obj;
|
||||
if(decl->nested){
|
||||
NameDict_ captured = frame->_locals.to_namedict();
|
||||
obj = VAR(Function({decl, is_simple, frame->_module, captured}));
|
||||
obj = VAR(Function({decl, frame->_module, captured}));
|
||||
captured->set(decl->code->name, obj);
|
||||
}else{
|
||||
obj = VAR(Function({decl, is_simple, frame->_module}));
|
||||
obj = VAR(Function({decl, frame->_module}));
|
||||
}
|
||||
PUSH(obj);
|
||||
} DISPATCH();
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <variant>
|
||||
#include <type_traits>
|
||||
|
||||
#define PK_VERSION "1.0.5"
|
||||
#define PK_VERSION "1.0.7"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
56
src/obj.h
56
src/obj.h
@ -17,14 +17,29 @@ using NativeFuncC = std::function<PyObject*(VM*, ArgsView)>;
|
||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||
#endif
|
||||
|
||||
typedef int (*LuaStyleFuncC)(VM*);
|
||||
typedef shared_ptr<CodeObject> CodeObject_;
|
||||
|
||||
struct FuncDecl {
|
||||
struct KwArg {
|
||||
int key; // index in co->varnames
|
||||
PyObject* value; // default value
|
||||
};
|
||||
CodeObject_ code; // code object of this function
|
||||
pod_vector<int> args; // indices in co->varnames
|
||||
pod_vector<KwArg> kwargs; // indices in co->varnames
|
||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested = false; // whether this function is nested
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
using FuncDecl_ = shared_ptr<FuncDecl>;
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
int argc;
|
||||
|
||||
// this is designed for lua style C bindings
|
||||
LuaStyleFuncC _lua_f;
|
||||
FuncDecl_ decl; // if this is not null, use ex call
|
||||
|
||||
using UserData = char[32];
|
||||
UserData _userdata;
|
||||
@ -53,39 +68,22 @@ struct NativeFunc {
|
||||
this->f = f;
|
||||
this->argc = argc;
|
||||
if(argc != -1) this->argc += (int)method;
|
||||
_lua_f = nullptr;
|
||||
_has_userdata = false;
|
||||
}
|
||||
|
||||
PyObject* operator()(VM* vm, ArgsView args) const;
|
||||
NativeFunc(NativeFuncC f, FuncDecl_ decl){
|
||||
this->f = f;
|
||||
this->argc = -1;
|
||||
this->decl = decl;
|
||||
_has_userdata = false;
|
||||
}
|
||||
|
||||
void check_size(VM* vm, ArgsView args) const;
|
||||
PyObject* call(VM* vm, ArgsView args) const;
|
||||
};
|
||||
|
||||
|
||||
struct NativeFuncEx{
|
||||
NativeFuncC f;
|
||||
};
|
||||
|
||||
typedef shared_ptr<CodeObject> CodeObject_;
|
||||
|
||||
struct FuncDecl {
|
||||
struct KwArg {
|
||||
int key; // index in co->varnames
|
||||
PyObject* value; // default value
|
||||
};
|
||||
CodeObject_ code; // code object of this function
|
||||
pod_vector<int> args; // indices in co->varnames
|
||||
pod_vector<KwArg> kwargs; // indices in co->varnames
|
||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested = false; // whether this function is nested
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
using FuncDecl_ = shared_ptr<FuncDecl>;
|
||||
|
||||
struct Function{
|
||||
FuncDecl_ decl;
|
||||
bool is_simple;
|
||||
PyObject* _module;
|
||||
NameDict_ _closure;
|
||||
};
|
||||
|
126
src/vm.h
126
src/vm.h
@ -690,15 +690,16 @@ public:
|
||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||
// new style binding api
|
||||
PyObject* bind(PyObject*, const Str&, NativeFuncC);
|
||||
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
||||
};
|
||||
|
||||
inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{
|
||||
inline void NativeFunc::check_size(VM* vm, ArgsView args) const{
|
||||
if(args.size() != argc && argc != -1) {
|
||||
vm->TypeError(fmt("expected ", argc, " arguments, got ", args.size()));
|
||||
}
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
if(f == nullptr) FATAL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline PyObject* NativeFunc::call(VM *vm, ArgsView args) const {
|
||||
return f(vm, args);
|
||||
}
|
||||
|
||||
@ -1238,52 +1239,10 @@ inline void VM::_unpack_as_dict(ArgsView args, Dict& dict){
|
||||
}
|
||||
}
|
||||
|
||||
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
PyObject** p1 = s_data._sp - KWARGC*2;
|
||||
PyObject** p0 = p1 - ARGC - 2;
|
||||
// [callable, <self>, args..., kwargs...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
PyObject* callable = p1[-(ARGC + 2)];
|
||||
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
||||
|
||||
// handle boundmethod, do a patch
|
||||
if(is_non_tagged_type(callable, tp_bound_method)){
|
||||
if(method_call) FATAL_ERROR();
|
||||
auto& bm = CAST(BoundMethod&, callable);
|
||||
callable = bm.func; // get unbound method
|
||||
p1[-(ARGC + 2)] = bm.func;
|
||||
p1[-(ARGC + 1)] = bm.self;
|
||||
method_call = true;
|
||||
// [unbound, self, args..., kwargs...]
|
||||
}
|
||||
|
||||
ArgsView args(p1 - ARGC - int(method_call), p1);
|
||||
|
||||
if(is_non_tagged_type(callable, tp_native_func)){
|
||||
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||
if(KWARGC != 0) TypeError("native_func does not accept keyword arguments");
|
||||
PyObject* ret = f(this, args);
|
||||
s_data.reset(p0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ArgsView kwargs(p1, s_data._sp);
|
||||
|
||||
if(false){ // native_func_ex
|
||||
|
||||
}
|
||||
|
||||
if(is_non_tagged_type(callable, tp_function)){
|
||||
/*****************_py_call*****************/
|
||||
// callable must be a `function` object
|
||||
if(s_data.is_overflow()) StackOverflowError();
|
||||
|
||||
const Function& fn = CAST(Function&, callable);
|
||||
|
||||
const FuncDecl_& decl = fn.decl;
|
||||
int decl_argc = decl->args.size();
|
||||
const CodeObject* co = fn.decl->code.get();
|
||||
inline void VM::_prepare_py_call(PyObject** buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl){
|
||||
const CodeObject* co = decl->code.get();
|
||||
int co_nlocals = co->varnames.size();
|
||||
int decl_argc = decl->args.size();
|
||||
|
||||
if(args.size() < decl_argc){
|
||||
vm->TypeError(fmt(
|
||||
@ -1292,20 +1251,7 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
));
|
||||
}
|
||||
|
||||
// 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() > decl_argc) TypeError("too many positional arguments");
|
||||
int spaces = co_nlocals - decl_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: decl->args) buffer[index] = args[i++];
|
||||
// set extra varnames to nullptr
|
||||
@ -1349,6 +1295,62 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
buffer[index] = kwargs[j+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
PyObject** p1 = s_data._sp - KWARGC*2;
|
||||
PyObject** p0 = p1 - ARGC - 2;
|
||||
// [callable, <self>, args..., kwargs...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
PyObject* callable = p1[-(ARGC + 2)];
|
||||
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
||||
|
||||
// handle boundmethod, do a patch
|
||||
if(is_non_tagged_type(callable, tp_bound_method)){
|
||||
if(method_call) FATAL_ERROR();
|
||||
auto& bm = CAST(BoundMethod&, callable);
|
||||
callable = bm.func; // get unbound method
|
||||
p1[-(ARGC + 2)] = bm.func;
|
||||
p1[-(ARGC + 1)] = bm.self;
|
||||
method_call = true;
|
||||
// [unbound, self, args..., kwargs...]
|
||||
}
|
||||
|
||||
ArgsView args(p1 - ARGC - int(method_call), p1);
|
||||
ArgsView kwargs(p1, s_data._sp);
|
||||
|
||||
static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
if(is_non_tagged_type(callable, tp_native_func)){
|
||||
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||
PyObject* ret;
|
||||
if(f.decl != nullptr){
|
||||
int co_nlocals = f.decl->code->varnames.size();
|
||||
_prepare_py_call(buffer, args, kwargs, f.decl);
|
||||
// copy buffer back to stack
|
||||
s_data.reset(args.begin());
|
||||
for(int j=0; j<co_nlocals; j++) PUSH(buffer[j]);
|
||||
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
||||
}else{
|
||||
if(KWARGC != 0) TypeError("old-style native_func does not accept keyword arguments");
|
||||
f.check_size(this, args);
|
||||
ret = f.call(this, args);
|
||||
}
|
||||
s_data.reset(p0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(is_non_tagged_type(callable, tp_function)){
|
||||
/*****************_py_call*****************/
|
||||
// callable must be a `function` object
|
||||
if(s_data.is_overflow()) StackOverflowError();
|
||||
|
||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||
const FuncDecl_& decl = fn.decl;
|
||||
const CodeObject* co = decl->code.get();
|
||||
int co_nlocals = co->varnames.size();
|
||||
|
||||
_prepare_py_call(buffer, args, kwargs, decl);
|
||||
|
||||
if(co->is_generator){
|
||||
s_data.reset(p0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user