This commit is contained in:
blueloveTH 2024-07-03 13:34:39 +08:00
parent 6ac3fdccdb
commit 8ae999ecdf
5 changed files with 236 additions and 38 deletions

View File

@ -87,6 +87,8 @@ py_Type pk_VM__new_type(pk_VM* self,
const py_TValue* module,
bool subclass_enabled);
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
// type registration
py_Type pk_str__register();
py_Type pk_bytes__register();

View File

@ -128,11 +128,11 @@ py_GlobalRef py_tpmagic(py_Type type, py_Name name);
// new style decl-based bindings
py_TmpRef py_bind(py_Ref obj, const char* sig, py_CFunction f);
py_TmpRef py_bind2(py_Ref obj,
const char* sig,
py_CFunction f,
BindType bt,
const char* docstring,
const py_Ref upvalue);
const char* sig,
py_CFunction f,
BindType bt,
const char* docstring,
const py_Ref upvalue);
// old style argc-based bindings
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, BindType bt);
@ -253,7 +253,7 @@ bool py_isidentical(const py_Ref, const py_Ref);
/// It assumes `argc + kwargc` arguments are already pushed to the stack.
/// The result will be set to `py_retval()`.
/// The stack size will be reduced by `argc + kwargc`.
bool pk_vectorcall(int argc, int kwargc, bool op_call);
bool py_vectorcall(uint16_t argc, uint16_t kwargc);
/// Call a function.
/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.
/// The result will be set to `py_retval()`.
@ -323,26 +323,43 @@ bool py_checktype(const py_Ref self, py_Type type);
/// %t: py_Type
/// %n: py_Name
enum py_MagicNames{
enum py_MagicNames {
py_MagicNames__NULL, // 0 is reserved
#define MAGIC_METHOD(x) x,
#include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD
#define MAGIC_METHOD(x) x,
#include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD
};
enum py_PredefinedTypes{
tp_object = 1, tp_type,
tp_int, tp_float, tp_bool, tp_str,
tp_list, tp_tuple,
tp_slice, tp_range, tp_module,
tp_function, tp_nativefunc, tp_bound_method,
tp_super, tp_exception, tp_bytes, tp_mappingproxy,
tp_dict, tp_property, tp_star_wrapper,
tp_staticmethod, tp_classmethod,
tp_none_type, tp_not_implemented_type,
enum py_PredefinedTypes {
tp_object = 1,
tp_type,
tp_int,
tp_float,
tp_bool,
tp_str,
tp_list,
tp_tuple,
tp_slice,
tp_range,
tp_module,
tp_function,
tp_nativefunc,
tp_bound_method,
tp_super,
tp_exception,
tp_bytes,
tp_mappingproxy,
tp_dict,
tp_property,
tp_star_wrapper,
tp_staticmethod,
tp_classmethod,
tp_none_type,
tp_not_implemented_type,
tp_ellipsis,
tp_syntax_error, tp_stop_iteration
tp_syntax_error,
tp_stop_iteration
};
#ifdef __cplusplus

View File

@ -49,9 +49,9 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
*SECOND() = *THIRD(); \
} while(0)
#define vectorcall_opcall(n) \
#define vectorcall_opcall(argc, kwargc) \
do { \
pk_FrameResult res = pk_vectorcall(n, 0, true); \
pk_FrameResult res = pk_VM__vectorcall(self, (argc), (kwargc), true); \
switch(res) { \
case RES_RETURN: PUSH(&self->last_retval); break; \
case RES_CALL: \
@ -269,7 +269,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} else {
INSERT_THIRD(); // [?, a, b]
*THIRD() = *magic; // [__getitem__, a, b]
vectorcall_opcall(2);
vectorcall_opcall(2, 0);
}
DISPATCH();
}
@ -322,7 +322,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} else {
INSERT_THIRD(); // [?, a, b]
*FOURTH() = *magic; // [__selitem__, a, b, val]
vectorcall_opcall(3);
vectorcall_opcall(3, 0);
POP(); // discard retval
}
DISPATCH();
@ -392,7 +392,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} else {
INSERT_THIRD(); // [?, a, b]
*THIRD() = *magic; // [__delitem__, a, b]
vectorcall_opcall(2);
vectorcall_opcall(2, 0);
POP(); // discard retval
}
DISPATCH();
@ -416,11 +416,11 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref f = py_getdict(&self->builtins, py_name("complex"));
assert(f != NULL);
py_TValue tmp = *TOP();
*TOP() = *f; // [complex]
py_newnull(SP()++); // [complex, NULL]
py_newint(SP()++, 0); // [complex, NULL, 0]
*SP()++ = tmp; // [complex, NULL, 0, x]
vectorcall_opcall(2); // [complex(x)]
*TOP() = *f; // [complex]
py_newnull(SP()++); // [complex, NULL]
py_newint(SP()++, 0); // [complex, NULL, 0]
*SP()++ = tmp; // [complex, NULL, 0, x]
vectorcall_opcall(2, 0); // [complex(x)]
DISPATCH();
}
case OP_BUILD_BYTES: {
@ -527,7 +527,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
} else {
INSERT_THIRD(); // [?, b, a]
*THIRD() = *magic; // [__contains__, a, b]
vectorcall_opcall(2);
vectorcall_opcall(2, 0);
}
bool res = py_tobool(TOP());
if(byte.arg) py_newbool(TOP(), !res);
@ -612,7 +612,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
assert(false);
}
case OP_CALL: {
assert(false);
pk_ManagedHeap__collect_if_needed(&self->heap);
vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8);
}
case OP_CALL_VARGS: {
assert(false);

View File

@ -1,10 +1,13 @@
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/memorypool.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/base.h"
#include "pocketpy/pocketpy.h"
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
static unsigned char* pk_default_import_file(const char* path) { return NULL; }
@ -69,7 +72,7 @@ void pk_VM__ctor(pk_VM* self) {
self->last_retval = PY_NULL;
self->has_error = false;
self->__curr_class = PY_NULL;
self->__cached_object_new = PY_NULL;
self->__dynamic_func_decl = NULL;
@ -196,6 +199,176 @@ py_Type pk_VM__new_type(pk_VM* self,
return index;
}
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bool opcall) {
py_Ref p1 = self->stack.sp - KWARGC * 2;
py_Ref p0 = p1 - ARGC - 2;
// [callable, <self>, args..., kwargs...]
// ^p0 ^p1 ^_sp
// handle boundmethod, do a patch
if(p0->type == tp_bound_method) {
assert(false);
assert(py_isnull(p0+1)); // self must be NULL
// BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
// callable = bm.func; // get unbound method
// callable_t = _tp(callable);
// p1[-(ARGC + 2)] = bm.func;
// p1[-(ARGC + 1)] = bm.self;
// [unbound, self, args..., kwargs...]
}
// PyVar* _base = args.begin();
py_Ref argv = py_isnull(p0+1) ? p0+2 : p0+1;
#if 0
if(callable_t == tp_function) {
/*****************_py_call*****************/
// check stack overflow
if(self->stack.sp > self->stack.end){
StackOverflowError();
return RES_ERROR;
}
const Function& fn = PK_OBJ_GET(Function, callable);
const CodeObject* co = fn.decl->code;
switch(fn.decl->type) {
case FuncType_NORMAL:
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
// copy buffer back to stack
s_data.reset(_base + co->nlocals);
for(int j = 0; j < co->nlocals; j++)
_base[j] = __vectorcall_buffer[j];
break;
case FuncType_SIMPLE:
if(args.size() != fn.decl->args.count) {
TypeError(pk_format("{} takes {} positional arguments but {} were given",
&co->name,
fn.decl->args.count,
args.size()));
}
if(!kwargs.empty()) {
TypeError(pk_format("{} takes no keyword arguments", &co->name));
}
// [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp
s_data.reset(_base + co->nlocals);
// initialize local variables to PY_NULL
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
break;
case FuncType_EMPTY:
if(args.size() != fn.decl->args.count) {
TypeError(pk_format("{} takes {} positional arguments but {} were given",
&co->name,
fn.decl->args.count,
args.size()));
}
if(!kwargs.empty()) {
TypeError(pk_format("{} takes no keyword arguments", &co->name));
}
s_data.reset(p0);
return None;
case FuncType_GENERATOR:
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
s_data.reset(p0);
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
return __py_generator(
callstack.popx(),
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
default: PK_UNREACHABLE()
};
// simple or normal
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
if(op_call) return pkpy_OP_CALL;
return __run_top_frame();
/*****************_py_call*****************/
}
#endif
if(p0->type == tp_nativefunc) {
// const auto& f = PK_OBJ_GET(NativeFunc, callable);
// PyVar ret;
// if(f.decl != nullptr) {
// int co_nlocals = f.decl->code->nlocals;
// __prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
// // copy buffer back to stack
// s_data.reset(_base + co_nlocals);
// for(int j = 0; j < co_nlocals; j++)
// _base[j] = __vectorcall_buffer[j];
// ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
// } else {
// if(f.argc != -1) {
// if(KWARGC != 0)
// TypeError(
// "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
// if(args.size() != f.argc) {
// vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
// }
// }
// ret = f.call(this, args);
// }
if(!p0->_cfunc(ARGC, argv)) return RES_ERROR;
self->stack.sp = p0;
return RES_RETURN;
}
#if 0
if(p0->type == tp_type) {
// [type, NULL, args..., kwargs...]
PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
PyVar obj;
assert(new_f && (!p0[1]));
if(PyVar__IS_OP(&new_f, &__cached_object_new)) {
// fast path for object.__new__
obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
} else {
PUSH(new_f);
PUSH(PY_NULL);
PUSH(callable); // cls
for(PyVar o: args)
PUSH(o);
for(PyVar o: kwargs)
PUSH(o);
// if obj is not an instance of `cls`, the behavior is undefined
obj = vectorcall(ARGC + 1, KWARGC);
}
// __init__
PyVar self;
callable = get_unbound_method(obj, __init__, &self, false);
if(callable) {
callable_t = _tp(callable);
// replace `NULL` with `self`
p1[-(ARGC + 2)] = callable;
p1[-(ARGC + 1)] = self;
// [init_f, self, args..., kwargs...]
vectorcall(ARGC, KWARGC);
// We just discard the return value of `__init__`
// in cpython it raises a TypeError if the return value is not None
} else {
// manually reset the stack
s_data.reset(p0);
}
return obj;
}
// handle `__call__` overload
PyVar self;
PyVar call_f = get_unbound_method(callable, __call__, &self, false);
if(self) {
p1[-(ARGC + 2)] = call_f;
p1[-(ARGC + 1)] = self;
// [call_f, self, args..., kwargs...]
return vectorcall(ARGC, KWARGC, op_call);
}
TypeError(_type_name(vm, callable_t).escape() + " object is not callable");
#endif
PK_UNREACHABLE();
}
/****************************************/
void PyObject__delete(PyObject* self) {
pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, self->type);
@ -221,4 +394,4 @@ void pk_ManagedHeap__mark(pk_ManagedHeap* self) {
// vm->obj_gc_mark(vm->__c.error);
// vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
// if(self->_gc_marker_ex) self->_gc_marker_ex((pkpy_VM*)vm);
}
}

View File

@ -6,6 +6,7 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/compiler/compiler.h"
#include <stdint.h>
pk_VM* pk_current_vm;
static pk_VM pk_default_vm;
@ -73,7 +74,8 @@ static void disassemble(CodeObject* co) {
c11_sbuf__write_cstr(&ss, OP_NAMES[byte.op]);
c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' ');
int padding = 24 - strlen(OP_NAMES[byte.op]);
for(int j = 0; j < padding; j++) c11_sbuf__write_char(&ss, ' ');
for(int j = 0; j < padding; j++)
c11_sbuf__write_char(&ss, ' ');
// _opcode_argstr(this, i, byte, co);
do {
@ -182,7 +184,10 @@ bool py_call(py_Ref f, int argc, py_Ref argv) { return -1; }
bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1; }
bool pk_vectorcall(int argc, int kwargc, bool op_call) { return -1; }
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
pk_VM* vm = pk_current_vm;
return pk_VM__vectorcall(vm, argc, kwargc, false) == RES_ERROR;
}
py_Ref py_retval() { return &pk_current_vm->last_retval; }