This commit is contained in:
blueloveTH 2023-06-29 02:01:08 +08:00
parent 0338a8c71c
commit 22e74a16a3
3 changed files with 60 additions and 35 deletions

View File

@ -99,14 +99,13 @@ __NEXT_STEP:;
TARGET(LOAD_FUNCTION) { TARGET(LOAD_FUNCTION) {
FuncDecl_ decl = co->func_decls[byte.arg]; 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; bool is_simple = decl->starred_kwarg==-1 && decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
int argc = decl->args.size();
PyObject* obj; PyObject* obj;
if(decl->nested){ if(decl->nested){
NameDict_ captured = frame->_locals.to_namedict(); NameDict_ captured = frame->_locals.to_namedict();
obj = VAR(Function({decl, is_simple, argc, frame->_module, captured})); obj = VAR(Function({decl, is_simple, frame->_module, captured}));
captured->set(decl->code->name, obj); captured->set(decl->code->name, obj);
}else{ }else{
obj = VAR(Function({decl, is_simple, argc, frame->_module})); obj = VAR(Function({decl, is_simple, frame->_module}));
} }
PUSH(obj); PUSH(obj);
} DISPATCH(); } DISPATCH();

View File

@ -30,8 +30,6 @@ struct NativeFunc {
UserData _userdata; UserData _userdata;
bool _has_userdata; bool _has_userdata;
const char* signature;
template <typename T> template <typename T>
void set_userdata(T data) { void set_userdata(T data) {
static_assert(std::is_trivially_copyable_v<T>); static_assert(std::is_trivially_copyable_v<T>);
@ -51,9 +49,8 @@ struct NativeFunc {
return reinterpret_cast<const T&>(_userdata); return reinterpret_cast<const T&>(_userdata);
} }
NativeFunc(NativeFuncC f, int argc, bool method, const char* sig=nullptr){ NativeFunc(NativeFuncC f, int argc, bool method){
this->f = f; this->f = f;
this->signature = sig;
this->argc = argc; this->argc = argc;
if(argc != -1) this->argc += (int)method; if(argc != -1) this->argc += (int)method;
_lua_f = nullptr; _lua_f = nullptr;
@ -63,6 +60,11 @@ struct NativeFunc {
PyObject* operator()(VM* vm, ArgsView args) const; PyObject* operator()(VM* vm, ArgsView args) const;
}; };
struct NativeFuncEx{
NativeFuncC f;
};
typedef shared_ptr<CodeObject> CodeObject_; typedef shared_ptr<CodeObject> CodeObject_;
struct FuncDecl { struct FuncDecl {
@ -84,7 +86,6 @@ using FuncDecl_ = shared_ptr<FuncDecl>;
struct Function{ struct Function{
FuncDecl_ decl; FuncDecl_ decl;
bool is_simple; bool is_simple;
int argc; // cached argc
PyObject* _module; PyObject* _module;
NameDict_ _closure; NameDict_ _closure;
}; };

View File

@ -461,19 +461,19 @@ public:
} }
template<int ARGC> template<int ARGC>
PyObject* bind_func(Str type, Str name, NativeFuncC fn, const char* sig=nullptr) { PyObject* bind_func(Str type, Str name, NativeFuncC fn) {
return bind_func<ARGC>(_find_type_object(type), name, fn, sig); return bind_func<ARGC>(_find_type_object(type), name, fn);
} }
template<int ARGC> template<int ARGC>
PyObject* bind_method(Str type, Str name, NativeFuncC fn, const char* sig=nullptr) { PyObject* bind_method(Str type, Str name, NativeFuncC fn) {
return bind_method<ARGC>(_find_type_object(type), name, fn, sig); return bind_method<ARGC>(_find_type_object(type), name, fn);
} }
template<int ARGC, typename __T> template<int ARGC, typename __T>
PyObject* bind_constructor(__T&& type, NativeFuncC fn, const char* sig=nullptr) { PyObject* bind_constructor(__T&& type, NativeFuncC fn) {
static_assert(ARGC==-1 || ARGC>=1); static_assert(ARGC==-1 || ARGC>=1);
return bind_func<ARGC>(std::forward<__T>(type), "__new__", fn, sig); return bind_func<ARGC>(std::forward<__T>(type), "__new__", fn);
} }
template<typename T, typename __T> template<typename T, typename __T>
@ -494,8 +494,8 @@ public:
} }
template<int ARGC> template<int ARGC>
PyObject* bind_builtin_func(Str name, NativeFuncC fn, const char* sig=nullptr) { PyObject* bind_builtin_func(Str name, NativeFuncC fn) {
return bind_func<ARGC>(builtins, name, fn, sig); return bind_func<ARGC>(builtins, name, fn);
} }
int normalized_index(int index, int size){ int normalized_index(int index, int size){
@ -681,13 +681,15 @@ public:
PyObject* format(Str, PyObject*); PyObject* format(Str, PyObject*);
void setattr(PyObject* obj, StrName name, PyObject* value); void setattr(PyObject* obj, StrName name, PyObject* value);
template<int ARGC> template<int ARGC>
PyObject* bind_method(PyObject*, Str, NativeFuncC, const char* sig=nullptr); PyObject* bind_method(PyObject*, Str, NativeFuncC);
template<int ARGC> template<int ARGC>
PyObject* bind_func(PyObject*, Str, NativeFuncC, const char* sig=nullptr); PyObject* bind_func(PyObject*, Str, NativeFuncC);
void _error(Exception); void _error(Exception);
PyObject* _run_top_frame(); PyObject* _run_top_frame();
void post_init(); void post_init();
PyObject* _py_generator(Frame&& frame, ArgsView buffer); PyObject* _py_generator(Frame&& frame, ArgsView buffer);
// new style binding api
PyObject* bind(PyObject*, const Str&, NativeFuncC);
}; };
inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{ inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{
@ -1267,27 +1269,34 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
ArgsView kwargs(p1, s_data._sp); ArgsView kwargs(p1, s_data._sp);
if(false){ // native_func_ex
}
if(is_non_tagged_type(callable, tp_function)){ if(is_non_tagged_type(callable, tp_function)){
/*****************_py_call*****************/ /*****************_py_call*****************/
// callable must be a `function` object // callable must be a `function` object
if(s_data.is_overflow()) StackOverflowError(); if(s_data.is_overflow()) StackOverflowError();
const Function& fn = CAST(Function&, callable); const Function& fn = CAST(Function&, callable);
const FuncDecl_& decl = fn.decl;
int decl_argc = decl->args.size();
const CodeObject* co = fn.decl->code.get(); const CodeObject* co = fn.decl->code.get();
int co_nlocals = co->varnames.size(); int co_nlocals = co->varnames.size();
if(args.size() < fn.argc){ if(args.size() < decl_argc){
vm->TypeError(fmt( vm->TypeError(fmt(
"expected ", fn.argc, " positional arguments, got ", args.size(), "expected ", decl_argc, " positional arguments, got ", args.size(),
" (", fn.decl->code->name, ')' " (", co->name, ')'
)); ));
} }
// if this function is simple, a.k.a, no kwargs and no *args and not a generator // 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 // we can use a fast path to avoid using buffer copy
if(fn.is_simple){ if(fn.is_simple){
if(args.size() > fn.argc) TypeError("too many positional arguments"); if(args.size() > decl_argc) TypeError("too many positional arguments");
int spaces = co_nlocals - fn.argc; int spaces = co_nlocals - decl_argc;
for(int j=0; j<spaces; j++) PUSH(PY_NULL); for(int j=0; j<spaces; j++) PUSH(PY_NULL);
callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin())); callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
if(op_call) return PY_OP_CALL; if(op_call) return PY_OP_CALL;
@ -1298,30 +1307,30 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES]; static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
// prepare args // prepare args
for(int index: fn.decl->args) buffer[index] = args[i++]; for(int index: decl->args) buffer[index] = args[i++];
// set extra varnames to nullptr // set extra varnames to nullptr
for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL; for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL;
// prepare kwdefaults // prepare kwdefaults
for(auto& kv: fn.decl->kwargs) buffer[kv.key] = kv.value; for(auto& kv: decl->kwargs) buffer[kv.key] = kv.value;
// handle *args // handle *args
if(fn.decl->starred_arg != -1){ if(decl->starred_arg != -1){
ArgsView vargs(args.begin() + i, args.end()); ArgsView vargs(args.begin() + i, args.end());
buffer[fn.decl->starred_arg] = VAR(vargs.to_tuple()); buffer[decl->starred_arg] = VAR(vargs.to_tuple());
i += vargs.size(); i += vargs.size();
}else{ }else{
// kwdefaults override // kwdefaults override
for(auto& kv: fn.decl->kwargs){ for(auto& kv: decl->kwargs){
if(i >= args.size()) break; if(i >= args.size()) break;
buffer[kv.key] = args[i++]; buffer[kv.key] = args[i++];
} }
if(i < args.size()) TypeError(fmt("too many arguments", " (", fn.decl->code->name, ')')); if(i < args.size()) TypeError(fmt("too many arguments", " (", decl->code->name, ')'));
} }
PyObject* vkwargs; PyObject* vkwargs;
if(fn.decl->starred_kwarg != -1){ if(decl->starred_kwarg != -1){
vkwargs = VAR(Dict(this)); vkwargs = VAR(Dict(this));
buffer[fn.decl->starred_kwarg] = vkwargs; buffer[decl->starred_kwarg] = vkwargs;
}else{ }else{
vkwargs = nullptr; vkwargs = nullptr;
} }
@ -1519,20 +1528,36 @@ inline void VM::setattr(PyObject* obj, StrName name, PyObject* value){
} }
template<int ARGC> template<int ARGC>
PyObject* VM::bind_method(PyObject* obj, Str name, NativeFuncC fn, const char* sig) { PyObject* VM::bind_method(PyObject* obj, Str name, NativeFuncC fn) {
check_non_tagged_type(obj, tp_type); check_non_tagged_type(obj, tp_type);
PyObject* nf = VAR(NativeFunc(fn, ARGC, true, sig)); PyObject* nf = VAR(NativeFunc(fn, ARGC, true));
obj->attr().set(name, nf); obj->attr().set(name, nf);
return nf; return nf;
} }
template<int ARGC> template<int ARGC>
PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn, const char* sig) { PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn) {
PyObject* nf = VAR(NativeFunc(fn, ARGC, false, sig)); PyObject* nf = VAR(NativeFunc(fn, ARGC, false));
obj->attr().set(name, nf); obj->attr().set(name, nf);
return nf; return nf;
} }
inline PyObject* VM::bind(PyObject* obj, const Str& sig, NativeFuncC fn){
CodeObject_ co;
try{
// fn(a, b, *c, d=1) -> None
co = compile("def " + sig + " : pass", "<bind>", EXEC_MODE);
}catch(Exception& e){
throw std::runtime_error(("invalid signature: " + sig).str());
}
if(co->func_decls.size() != 1){
throw std::runtime_error("expected 1 function declaration");
}
FuncDecl_ decl = co->func_decls[0];
// return VAR(NativeFuncEx(fn, argc, false, sig));
return nullptr;
}
inline void VM::_error(Exception e){ inline void VM::_error(Exception e){
if(callstack.empty()){ if(callstack.empty()){
e.is_re = false; e.is_re = false;