This commit is contained in:
blueloveTH 2024-06-30 02:38:38 +08:00
parent 5be3300554
commit cde78ea481
11 changed files with 335 additions and 70 deletions

View File

@ -63,8 +63,8 @@ typedef struct pk_VM {
py_TValue last_retval;
py_TValue reg[8]; // users' registers
PyObject* __curr_class;
PyObject* __cached_object_new;
py_TValue __curr_class;
py_TValue __cached_object_new;
FuncDecl_ __dynamic_func_decl;
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];

View File

@ -29,7 +29,8 @@ typedef struct py_TValue{
};
} py_TValue;
static_assert(sizeof(py_TValue) <= 16, "!sizeof(py_TValue) <= 16");
// 16 bytes to make py_arg() macro work
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
/* predefined vars */
static const py_Type tp_object = {1}, tp_type = {2};

View File

@ -40,12 +40,12 @@ void py_newbool(py_Ref, bool);
void py_newstr(py_Ref, const char*);
void py_newstrn(py_Ref, const char*, int);
// void py_newfstr(py_Ref, const char*, ...);
// void py_newbytes(py_Ref, const uint8_t*, int);
void py_newbytes(py_Ref, const unsigned char*, int);
void py_newnone(py_Ref);
void py_newnull(py_Ref);
void py_newtuple(py_Ref, int);
// void py_newlist(py_Ref);
void py_newtuple(py_Ref, int count);
void py_newlist(py_Ref);
// new style decl-based function
void py_newfunction(py_Ref out, py_CFunction, const char* sig);
@ -101,6 +101,8 @@ bool py_istype(const py_Ref, py_Type);
// bool py_issubclass(py_Type derived, py_Type base);
/************* References *************/
#define py_arg(i) (py_Ref)((char*)argv+((i)<<4))
py_Ref py_getreg(int i);
void py_setreg(int i, const py_Ref val);
@ -114,9 +116,13 @@ py_Ref py_getupvalue(py_Ref self);
void py_setupvalue(py_Ref self, const py_Ref val);
/// Gets the attribute of the object.
int py_getattr(const py_Ref self, py_Name name, py_Ref out);
bool py_getattr(const py_Ref self, py_Name name, py_Ref out);
/// Gets the unbound method of the object.
bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self);
/// Sets the attribute of the object.
int py_setattr(py_Ref self, py_Name name, const py_Ref val);
/// Deletes the attribute of the object.
int py_delattr(py_Ref self, py_Name name);
/// Equivalent to `*dst = *src`.
void py_assign(py_Ref dst, const py_Ref src);
@ -193,6 +199,10 @@ void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val);
void py_dict__delitem(py_Ref self, const py_Ref key);
void py_dict__clear(py_Ref self);
// internal functions
typedef struct pk_TypeInfo pk_TypeInfo;
pk_TypeInfo* pk_tpinfo(const py_Ref self);
#ifdef __cplusplus
}
#endif

View File

@ -29,14 +29,12 @@ OPCODE(LOAD_ATTR)
OPCODE(LOAD_CLASS_GLOBAL)
OPCODE(LOAD_METHOD)
OPCODE(LOAD_SUBSCR)
OPCODE(LOAD_SUBSCR_FAST)
OPCODE(STORE_FAST)
OPCODE(STORE_NAME)
OPCODE(STORE_GLOBAL)
OPCODE(STORE_ATTR)
OPCODE(STORE_SUBSCR)
OPCODE(STORE_SUBSCR_FAST)
OPCODE(DELETE_FAST)
OPCODE(DELETE_NAME)

View File

@ -1001,26 +1001,14 @@ void SubscrExpr__emit_(Expr* self_, Ctx* ctx) {
SubscrExpr* self = (SubscrExpr*)self_;
vtemit_(self->lhs, ctx);
vtemit_(self->rhs, ctx);
Bytecode last_bc = c11_vector__back(Bytecode, &ctx->co->codes);
if(self->rhs->vt->is_name && last_bc.op == OP_LOAD_FAST) {
Ctx__revert_last_emit_(ctx);
Ctx__emit_(ctx, OP_LOAD_SUBSCR_FAST, last_bc.arg, self->line);
} else {
Ctx__emit_(ctx, OP_LOAD_SUBSCR, BC_NOARG, self->line);
}
Ctx__emit_(ctx, OP_LOAD_SUBSCR, BC_NOARG, self->line);
}
bool SubscrExpr__emit_store(Expr* self_, Ctx* ctx) {
SubscrExpr* self = (SubscrExpr*)self_;
vtemit_(self->lhs, ctx);
vtemit_(self->rhs, ctx);
Bytecode last_bc = c11_vector__back(Bytecode, &ctx->co->codes);
if(self->rhs->vt->is_name && last_bc.op == OP_LOAD_FAST) {
Ctx__revert_last_emit_(ctx);
Ctx__emit_(ctx, OP_STORE_SUBSCR_FAST, last_bc.arg, self->line);
} else {
Ctx__emit_(ctx, OP_STORE_SUBSCR, BC_NOARG, self->line);
}
Ctx__emit_(ctx, OP_STORE_SUBSCR, BC_NOARG, self->line);
return true;
}

View File

@ -8,6 +8,8 @@ int UnboundLocalError(py_Name name) { return -1; }
int NameError(py_Name name) { return -1; }
#define AttributeError(obj, name)
#define DISPATCH() \
do { \
frame->ip++; \
@ -26,15 +28,39 @@ int NameError(py_Name name) { return -1; }
/* Stack manipulation macros */
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
#define TOP() self->stack.sp[-1]
#define SECOND() self->stack.sp[-2]
#define THIRD() self->stack.sp[-3]
#define TOP() (self->stack.sp - 1)
#define SECOND() (self->stack.sp - 2)
#define THIRD() (self->stack.sp - 3)
#define FOURTH() (self->stack.sp - 4)
#define STACK_SHRINK(n) (self->stack.sp -= n)
#define PUSH(v) (*self->stack.sp++ = v)
#define PUSH(v) (*self->stack.sp++ = *v)
#define POP() (--self->stack.sp)
#define POPX() (*--self->stack.sp)
#define SP() (self->stack.sp)
static void pack_stack_values(int n) {
assert(n > 1);
pk_VM* self = pk_current_vm;
py_TValue tmp;
py_newtuple(&tmp, n);
for(int i = 0; i < n; i++)
py_tuple__setitem(&tmp, i, SP() - n + i);
STACK_SHRINK(n);
PUSH(&tmp);
}
// n == 1 is the most likely result
#define HANDLE_RETVAL(n) \
if(n != 1) { \
if(n == 0) { \
PUSH(&self->None); \
} else if(n > 1) { \
pack_stack_values(n); \
} else { \
goto __ERROR; \
} \
}
pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
Frame* frame = self->top_frame;
const Frame* base_frame = frame;
@ -72,39 +98,37 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
PUSH(SECOND()); // [a, b, a, b]
DISPATCH();
case OP_ROT_TWO: {
py_TValue tmp = TOP();
TOP() = SECOND();
SECOND() = tmp;
py_TValue tmp = *TOP();
*TOP() = *SECOND();
*SECOND() = tmp;
DISPATCH();
}
case OP_ROT_THREE: {
// [a, b, c] -> [c, a, b]
py_TValue _0 = TOP();
TOP() = SECOND();
SECOND() = THIRD();
THIRD() = _0;
py_TValue tmp = *TOP();
*TOP() = *SECOND();
*SECOND() = *THIRD();
*THIRD() = tmp;
DISPATCH();
}
case OP_PRINT_EXPR:
if(TOP().type != tp_none_type) {
int err = py_repr(&TOP());
if(TOP()->type != tp_none_type) {
int err = py_repr(TOP());
if(err) goto __ERROR;
self->_stdout("%s\n", py_tostr(&TOP()));
self->_stdout("%s\n", py_tostr(TOP()));
POP();
}
POP();
DISPATCH();
/*****************************************/
case OP_LOAD_CONST:
PUSH(c11__getitem(py_TValue, &frame->co->consts, byte.arg));
DISPATCH();
case OP_LOAD_NONE: PUSH(self->None); DISPATCH();
case OP_LOAD_TRUE: PUSH(self->True); DISPATCH();
case OP_LOAD_FALSE: PUSH(self->False); DISPATCH();
case OP_LOAD_CONST: PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); DISPATCH();
case OP_LOAD_NONE: PUSH(&self->None); DISPATCH();
case OP_LOAD_TRUE: PUSH(&self->True); DISPATCH();
case OP_LOAD_FALSE: PUSH(&self->False); DISPATCH();
/*****************************************/
case OP_LOAD_SMALL_INT: py_newint(SP()++, (int64_t)(int16_t)byte.arg); DISPATCH();
/*****************************************/
case OP_LOAD_ELLIPSIS: PUSH(self->Ellipsis); DISPATCH();
case OP_LOAD_ELLIPSIS: PUSH(&self->Ellipsis); DISPATCH();
case OP_LOAD_FUNCTION: {
// FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
// py_TValue obj;
@ -126,8 +150,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
DISPATCH();
/*****************************************/
case OP_LOAD_FAST: {
PUSH(frame->locals[byte.arg]);
if(py_isnull(&TOP())) {
PUSH(&frame->locals[byte.arg]);
if(py_isnull(TOP())) {
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
UnboundLocalError(name);
goto __ERROR;
@ -142,22 +166,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
UnboundLocalError(name);
goto __ERROR;
}
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = Frame__f_closure_try_get(frame, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = Frame__f_globals_try_get(frame, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&self->builtins, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
NameError(name);
@ -167,17 +191,17 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Name name = byte.arg;
py_Ref tmp = Frame__f_closure_try_get(frame, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = Frame__f_globals_try_get(frame, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&self->builtins, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
NameError(name);
@ -187,27 +211,203 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Name name = byte.arg;
py_Ref tmp = Frame__f_globals_try_get(frame, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&self->builtins, name);
if(tmp != NULL) {
PUSH(*tmp);
PUSH(tmp);
DISPATCH();
}
NameError(name);
goto __ERROR;
}
case OP_LOAD_ATTR: {
int err = py_getattr(&TOP(), byte.arg, &TOP());
if(err) goto __ERROR;
if(!py_getattr(TOP(), byte.arg, TOP())) {
AttributeError(TOP(), byte.arg);
goto __ERROR;
}
DISPATCH();
}
/*******************/
case OP_LOAD_CLASS_GLOBAL: {
assert(self->__curr_class.type);
py_Name name = byte.arg;
if(py_getattr(&self->__curr_class, name, SP())) {
SP()++;
DISPATCH();
}
// load global if attribute not found
py_Ref tmp = Frame__f_globals_try_get(frame, name);
if(tmp) {
PUSH(tmp);
DISPATCH();
}
tmp = py_getdict(&self->builtins, name);
if(tmp) {
PUSH(tmp);
DISPATCH();
}
NameError(name);
goto __ERROR;
}
case OP_LOAD_METHOD: {
// `py_getunboundmethod` never fails on `fallback=true`
py_getunboundmethod(TOP(), byte.arg, true, TOP(), SP());
SP()++;
DISPATCH();
}
case OP_LOAD_SUBSCR: {
// [a, b] -> a[b]
int n = py_callmethod(SECOND(), __getitem__, TOP());
HANDLE_RETVAL(n);
// [a, b, retval]
*THIRD() = *TOP(); // [retval, b, retval]
STACK_SHRINK(2); // [retval]
DISPATCH();
}
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
case OP_STORE_NAME: {
py_Name _name = byte.arg;
py_TValue _0 = POPX();
if(frame->function) {
py_Ref slot = Frame__f_locals_try_get(frame, _name);
if(slot != NULL) {
*slot = _0; // store in locals if possible
} else {
// Function& func = frame->_callable->as<Function>();
// if(func.decl == __dynamic_func_decl) {
// assert(func._closure != nullptr);
// func._closure->set(_name, _0);
// } else {
// NameError(_name);
// goto __ERROR;
// }
}
} else {
pk_NameDict__set(Frame__f_globals(frame), _name, _0);
}
DISPATCH();
}
case OP_STORE_GLOBAL:
pk_NameDict__set(Frame__f_globals(frame), byte.arg, POPX());
DISPATCH();
// ...
case OP_STORE_ATTR: {
int err = py_setattr(TOP(), byte.arg, SECOND());
if(err) goto __ERROR;
STACK_SHRINK(2);
DISPATCH();
}
case OP_STORE_SUBSCR: {
// [val, a, b] -> a[b] = val
py_TValue* backup = SP();
PUSH(THIRD()); // [val, a, b, val]
bool ok = py_getunboundmethod(THIRD(), __setitem__, false, FOURTH(), THIRD());
if(!ok) {
// __setitem__ not found
goto __ERROR;
}
// [__setitem__, self, b, val]
int n = py_vectorcall(3, 0);
if(n < 0) goto __ERROR;
SP() = backup; // discard retval if any
DISPATCH();
}
case OP_DELETE_FAST: {
py_Ref tmp = &frame->locals[byte.arg];
if(py_isnull(tmp)) {
UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
goto __ERROR;
}
py_newnull(tmp);
DISPATCH();
}
case OP_DELETE_NAME: {
StrName name = byte.arg;
if(frame->function) {
py_TValue* slot = Frame__f_locals_try_get(frame, name);
if(slot) {
py_newnull(slot);
} else {
// Function& func = frame->_callable->as<Function>();
// if(func.decl == __dynamic_func_decl) {
// assert(func._closure != nullptr);
// bool ok = func._closure->del(_name);
// if(!ok) vm->NameError(_name);
// } else {
// vm->NameError(_name);
// }
}
} else {
// if(!frame->f_globals().del(_name)) vm->NameError(_name);
bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
if(!ok) {
NameError(name);
goto __ERROR;
}
}
DISPATCH();
}
case OP_DELETE_GLOBAL: {
StrName name = byte.arg;
bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
if(!ok) {
NameError(name);
goto __ERROR;
}
DISPATCH();
}
/*******************/
case OP_DELETE_ATTR: {
int err = py_delattr(TOP(), byte.arg);
if(err) goto __ERROR;
POP();
DISPATCH();
}
case OP_DELETE_SUBSCR: {
// [a, b] -> del a[b]
py_Ref backup = SP();
int n = py_callmethod(SECOND(), __delitem__, TOP());
if(n < 0) { goto __ERROR; }
SP() = backup; // discard retval if any
DISPATCH();
}
/*****************************************/
case OP_BUILD_LONG: {
py_Ref _0 = py_getdict(&self->builtins, pk_id_long);
assert(_0 != NULL);
int n = py_call(_0, TOP());
if(n < 0) goto __ERROR;
assert(n == 1);
// [x, long(x)]
*SECOND() = *TOP(); // [long(x), long(x)]
POP(); // [long(x)]
DISPATCH();
}
case OP_BUILD_IMAG: {
py_Ref _0 = py_getdict(&self->builtins, pk_id_complex);
assert(_0 != NULL);
py_TValue zero;
py_newint(&zero, 0);
int n = py_call(_0, &zero, TOP());
if(n < 0) goto __ERROR;
assert(n == 1);
// [x, complex(0, x)]
*SECOND() = *TOP(); // [complex(0, x), complex(0, x)]
POP(); // [complex(0, x)]
DISPATCH();
}
case OP_BUILD_BYTES: {
py_Str* s = py_touserdata(TOP());
unsigned char* p = (unsigned char*)malloc(s->size);
memcpy(p, py_Str__data(s), s->size);
py_newbytes(SP()++, p, s->size);
DISPATCH();
}
case OP_BUILD_TUPLE: {
py_TValue tmp;
py_newtuple(&tmp, byte.arg);
@ -216,19 +416,59 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_tuple__setitem(&tmp, i, begin + i);
}
SP() = begin;
PUSH(tmp);
PUSH(&tmp);
DISPATCH();
}
// case OP_BUILD_LIST: {
// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
// STACK_SHRINK(byte.arg);
// PUSH(_0);
// DISPATCH();
// }
// case OP_BUILD_DICT: {
// if(byte.arg == 0) {
// PUSH(VAR(Dict()));
// DISPATCH()
// }
// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
// _0 = call(_t(tp_dict), _0);
// STACK_SHRINK(byte.arg);
// PUSH(_0);
// DISPATCH();
// }
// case OP_BUILD_SET: {
// PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
// _0 = call(builtins->attr()[pk_id_set], _0);
// STACK_SHRINK(byte.arg);
// PUSH(_0);
// DISPATCH();
// }
// case OP_BUILD_SLICE: {
// PyVar _2 = POPX(); // step
// PyVar _1 = POPX(); // stop
// PyVar _0 = POPX(); // start
// PUSH(VAR(Slice(_0, _1, _2)));
// DISPATCH();
// }
// case OP_BUILD_STRING: {
// SStream ss;
// ArgsView view = STACK_VIEW(byte.arg);
// for(PyVar obj: view)
// ss << py_str(obj);
// STACK_SHRINK(byte.arg);
// PUSH(VAR(ss.str()));
// DISPATCH();
// }
/**************************** */
case OP_RETURN_VALUE: {
py_TValue tmp = byte.arg == BC_NOARG ? POPX() : self->None;
py_TValue tmp = byte.arg == BC_NOARG ? POPX() : self->None;
pk_VM__pop_frame(self);
if(frame == base_frame) { // [ frameBase<- ]
self->last_retval = tmp;
return RES_RETURN;
} else {
frame = self->top_frame;
PUSH(tmp);
PUSH(&tmp);
goto __NEXT_FRAME;
}
DISPATCH();

View File

@ -175,7 +175,7 @@ static int _py_int__invert__(int argc, py_Ref argv) {
}
static int _py_int__bit_length(int argc, py_Ref argv) {
int64_t x = py_toint(&argv[0]);
int64_t x = py_toint(py_arg(0));
if(x < 0) x = -x;
int bits = 0;
while(x) {

View File

@ -58,8 +58,8 @@ void pk_VM__ctor(pk_VM* self){
self->last_error = NULL;
self->last_retval = PY_NULL;
self->__curr_class = NULL;
self->__cached_object_new = NULL;
self->__curr_class = PY_NULL;
self->__cached_object_new = PY_NULL;
self->__dynamic_func_decl = NULL;
pk_ManagedHeap__ctor(&self->heap, self);

View File

@ -15,14 +15,14 @@ int py_repr(const py_Ref val) {
return py_callmethod(val, __repr__);
}
int py_getattr(const py_Ref self, py_Name name, py_Ref out){
return -1;
bool py_getattr(const py_Ref self, py_Name name, py_Ref out){
return true;
}
int py_setattr(py_Ref self, py_Name name, const py_Ref val){
return -1;
}
int py_callmethod(py_Ref self, py_Name name, ...){
int py_delattr(py_Ref self, py_Name name){
return -1;
}
}

View File

@ -39,6 +39,18 @@ void py_newstrn(py_Ref out, const char* data, int size) {
out->_obj = obj;
}
void py_newbytes(py_Ref out, const unsigned char* data, int size) {
pk_ManagedHeap* heap = &pk_current_vm->heap;
// 4 bytes size + data
PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(int) + size);
int* psize = (int*)PyObject__value(obj);
*psize = size;
memcpy(psize + 1, data, size);
out->type = tp_bytes;
out->is_ptr = true;
out->_obj = obj;
}
void py_newnone(py_Ref out) {
pk_VM* vm = pk_current_vm;
*out = vm->None;

View File

@ -45,4 +45,20 @@ int py_eval(const char* source, py_Ref out) {
return 0;
}
PK_UNREACHABLE();
}
int py_call(py_Ref callable, ...){
return -1;
}
int py_callmethod(py_Ref self, py_Name name, ...){
return -1;
}
int py_vectorcall(int argc, int kwargc){
return -1;
}
bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self){
return -1;
}