This commit is contained in:
blueloveTH 2025-02-28 15:09:19 +08:00
parent 2800f5eedb
commit 330e005881
7 changed files with 59 additions and 72 deletions

View File

@ -34,9 +34,8 @@ typedef struct Frame {
py_StackRef p0; // unwinding base py_StackRef p0; // unwinding base
py_GlobalRef module; py_GlobalRef module;
py_Ref globals; // a module object or a dict object py_Ref globals; // a module object or a dict object
py_Ref locals; // locals base or a proxy object (such as dict) py_Ref locals;
bool is_p0_function; bool is_locals_special;
bool is_locals_proxy;
int ip; int ip;
UnwindTarget* uw_list; UnwindTarget* uw_list;
} Frame; } Frame;
@ -46,8 +45,7 @@ Frame* Frame__new(const CodeObject* co,
py_GlobalRef module, py_GlobalRef module,
py_Ref globals, py_Ref globals,
py_Ref locals, py_Ref locals,
bool is_p0_function, bool is_locals_special);
bool is_locals_proxy);
void Frame__delete(Frame* self); void Frame__delete(Frame* self);
int Frame__lineno(const Frame* self); int Frame__lineno(const Frame* self);

View File

@ -181,8 +181,8 @@ FrameResult VM__run_top_frame(VM* self) {
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function)); Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
Function__ctor(ud, decl, frame->module, frame->globals); Function__ctor(ud, decl, frame->module, frame->globals);
if(decl->nested) { if(decl->nested) {
if(frame->is_locals_proxy) { if(frame->is_locals_special) {
RuntimeError("cannot create closure from locals proxy"); RuntimeError("cannot create closure from special locals");
goto __ERROR; goto __ERROR;
} }
ud->closure = FastLocals__to_namedict(frame->locals, frame->co); ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
@ -198,7 +198,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH(); DISPATCH();
/*****************************************/ /*****************************************/
case OP_LOAD_FAST: { case OP_LOAD_FAST: {
assert(!frame->is_locals_proxy); assert(!frame->is_locals_special);
PUSH(&frame->locals[byte.arg]); PUSH(&frame->locals[byte.arg]);
if(py_isnil(TOP())) { if(py_isnil(TOP())) {
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg); py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
@ -341,7 +341,7 @@ FrameResult VM__run_top_frame(VM* self) {
goto __ERROR; goto __ERROR;
} }
case OP_STORE_FAST: { case OP_STORE_FAST: {
assert(!frame->is_locals_proxy); assert(!frame->is_locals_special);
frame->locals[byte.arg] = POPX(); frame->locals[byte.arg] = POPX();
DISPATCH(); DISPATCH();
} }
@ -392,7 +392,7 @@ FrameResult VM__run_top_frame(VM* self) {
goto __ERROR; goto __ERROR;
} }
case OP_DELETE_FAST: { case OP_DELETE_FAST: {
assert(!frame->is_locals_proxy); assert(!frame->is_locals_special);
py_Ref tmp = &frame->locals[byte.arg]; py_Ref tmp = &frame->locals[byte.arg];
if(py_isnil(tmp)) { if(py_isnil(tmp)) {
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg); py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);
@ -1146,7 +1146,7 @@ FrameResult VM__run_top_frame(VM* self) {
py_BaseException__stpush(&self->curr_exception, py_BaseException__stpush(&self->curr_exception,
frame->co->src, frame->co->src,
Frame__lineno(frame), Frame__lineno(frame),
frame->is_p0_function ? frame->co->name->data : NULL); !frame->is_locals_special ? frame->co->name->data : NULL);
__ERROR_RE_RAISE: __ERROR_RE_RAISE:
do { do {
} while(0); } while(0);

View File

@ -52,11 +52,12 @@ Frame* Frame__new(const CodeObject* co,
py_GlobalRef module, py_GlobalRef module,
py_Ref globals, py_Ref globals,
py_Ref locals, py_Ref locals,
bool is_p0_function, bool is_locals_special) {
bool is_locals_proxy) {
assert(module->type == tp_module); assert(module->type == tp_module);
assert(globals->type == tp_module || globals->type == tp_dict); assert(globals->type == tp_module || globals->type == tp_dict);
assert(locals->type == tp_locals || locals->type == tp_dict || locals->type == tp_nil); if(is_locals_special) {
assert(locals->type == tp_nil || locals->type == tp_locals || locals->type == tp_dict);
}
Frame* self = FixedMemoryPool__alloc(&pk_current_vm->pool_frame); Frame* self = FixedMemoryPool__alloc(&pk_current_vm->pool_frame);
self->f_back = NULL; self->f_back = NULL;
self->co = co; self->co = co;
@ -64,8 +65,7 @@ Frame* Frame__new(const CodeObject* co,
self->module = module; self->module = module;
self->globals = globals; self->globals = globals;
self->locals = locals; self->locals = locals;
self->is_p0_function = is_p0_function; self->is_locals_special = is_locals_special;
self->is_locals_proxy = is_locals_proxy;
self->ip = -1; self->ip = -1;
self->uw_list = NULL; self->uw_list = NULL;
return self; return self;
@ -81,8 +81,7 @@ void Frame__delete(Frame* self) {
} }
py_StackRef Frame__locals_sp(Frame* self) { py_StackRef Frame__locals_sp(Frame* self) {
if(!self->is_locals_proxy) { return self->locals; } return !self->is_locals_special ? self->locals : self->p0;
return self->p0;
} }
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) { int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
@ -120,7 +119,7 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
void Frame__gc_mark(Frame* self) { void Frame__gc_mark(Frame* self) {
pk__mark_value(self->globals); pk__mark_value(self->globals);
if(self->is_locals_proxy) pk__mark_value(self->locals); if(self->is_locals_special) pk__mark_value(self->locals);
CodeObject__gc_mark(self->co); CodeObject__gc_mark(self->co);
} }
@ -166,12 +165,12 @@ int Frame__delglobal(Frame* self, py_Name name) {
} }
int Frame__getlocal(Frame* self, py_Name name) { int Frame__getlocal(Frame* self, py_Name name) {
if(self->is_locals_proxy) { if(self->is_locals_special) {
if(self->locals->type == tp_locals) { switch(self->locals->type) {
self = self->locals->_ptr; case tp_locals: self = self->locals->_ptr; break;
} else { case tp_dict: return py_dict_getitem(self->locals, py_name2ref(name));
assert(self->locals->type == tp_dict); case tp_nil: return 0;
return py_dict_getitem(self->locals, py_name2ref(name)); default: c11__unreachable();
} }
} }
py_Ref slot = Frame__getlocal_noproxy(self, name); py_Ref slot = Frame__getlocal_noproxy(self, name);
@ -185,12 +184,12 @@ int Frame__getlocal(Frame* self, py_Name name) {
} }
bool Frame__setlocal(Frame* self, py_Name name, py_TValue* val) { bool Frame__setlocal(Frame* self, py_Name name, py_TValue* val) {
if(self->is_locals_proxy) { if(self->is_locals_special) {
if(self->locals->type == tp_locals) { switch(self->locals->type) {
self = self->locals->_ptr; case tp_locals: self = self->locals->_ptr; break;
} else { case tp_dict: return py_dict_setitem(self->locals, py_name2ref(name), val);
assert(self->locals->type == tp_dict); case tp_nil: return false;
return py_dict_setitem(self->locals, py_name2ref(name), val); default: c11__unreachable();
} }
} }
py_Ref slot = Frame__getlocal_noproxy(self, name); py_Ref slot = Frame__getlocal_noproxy(self, name);
@ -200,12 +199,12 @@ bool Frame__setlocal(Frame* self, py_Name name, py_TValue* val) {
} }
int Frame__dellocal(Frame* self, py_Name name) { int Frame__dellocal(Frame* self, py_Name name) {
if(self->is_locals_proxy) { if(self->is_locals_special) {
if(self->locals->type == tp_locals) { switch(self->locals->type) {
self = self->locals->_ptr; case tp_locals: self = self->locals->_ptr; break;
} else { case tp_dict: return py_dict_delitem(self->locals, py_name2ref(name));
assert(self->locals->type == tp_dict); case tp_nil: return 0;
return py_dict_delitem(self->locals, py_name2ref(name)); default: c11__unreachable();
} }
} }
py_Ref slot = Frame__getlocal_noproxy(self, name); py_Ref slot = Frame__getlocal_noproxy(self, name);
@ -219,14 +218,15 @@ int Frame__dellocal(Frame* self, py_Name name) {
} }
py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name) { py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name) {
assert(!self->is_locals_proxy); assert(!self->is_locals_special);
int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1); int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1);
if(index == -1) return NULL; if(index == -1) return NULL;
return &self->locals[index]; return &self->locals[index];
} }
py_Ref Frame__getclosure(Frame* self, py_Name name) { py_Ref Frame__getclosure(Frame* self, py_Name name) {
if(!self->is_p0_function) return NULL; if(self->is_locals_special) return NULL;
assert(self->p0->type == tp_function);
Function* ud = py_touserdata(self->p0); Function* ud = py_touserdata(self->p0);
if(ud->closure == NULL) return NULL; if(ud->closure == NULL) return NULL;
return NameDict__try_get(ud->closure, name); return NameDict__try_get(ud->closure, name);

View File

@ -28,9 +28,7 @@ static bool generator__next__(int argc, py_Ref argv) {
if(ud->state == 2) return StopIteration(); if(ud->state == 2) return StopIteration();
// reset frame->p0 // reset frame->p0
if(ud->frame->is_locals_proxy){ assert(!ud->frame->is_locals_special);
return RuntimeError("cannot resume generator with locals proxy");
}
int locals_offset = ud->frame->locals - ud->frame->p0; int locals_offset = ud->frame->locals - ud->frame->p0;
ud->frame->p0 = py_peek(0); ud->frame->p0 = py_peek(0);
ud->frame->locals = ud->frame->p0 + locals_offset; ud->frame->locals = ud->frame->p0 + locals_offset;

View File

@ -485,8 +485,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
// submit the call // submit the call
if(!fn->cfunc) { if(!fn->cfunc) {
// python function // python function
VM__push_frame(self, VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
Frame__new(co, p0, fn->module, fn->globals, argv, true, false));
return opcall ? RES_CALL : VM__run_top_frame(self); return opcall ? RES_CALL : VM__run_top_frame(self);
} else { } else {
// decl-based binding // decl-based binding
@ -515,8 +514,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
// submit the call // submit the call
if(!fn->cfunc) { if(!fn->cfunc) {
// python function // python function
VM__push_frame(self, VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
Frame__new(co, p0, fn->module, fn->globals, argv, true, false));
return opcall ? RES_CALL : VM__run_top_frame(self); return opcall ? RES_CALL : VM__run_top_frame(self);
} else { } else {
// decl-based binding // decl-based binding
@ -532,7 +530,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
// copy buffer back to stack // copy buffer back to stack
self->stack.sp = argv + co->nlocals; self->stack.sp = argv + co->nlocals;
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue)); memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, true, false); Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, false);
pk_newgenerator(py_retval(), frame, p0, self->stack.sp); pk_newgenerator(py_retval(), frame, p0, self->stack.sp);
self->stack.sp = p0; // reset the stack self->stack.sp = p0; // reset the stack
return RES_RETURN; return RES_RETURN;

View File

@ -54,7 +54,7 @@ bool pk_exec(CodeObject* co, py_Ref module) {
assert(module->type == tp_module); assert(module->type == tp_module);
py_StackRef sp = vm->stack.sp; py_StackRef sp = vm->stack.sp;
Frame* frame = Frame__new(co, sp, module, module, py_NIL(), false, false); Frame* frame = Frame__new(co, sp, module, module, py_NIL(), true);
VM__push_frame(vm, frame); VM__push_frame(vm, frame);
FrameResult res = VM__run_top_frame(vm); FrameResult res = VM__run_top_frame(vm);
if(res == RES_ERROR) return false; if(res == RES_ERROR) return false;
@ -76,7 +76,7 @@ bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) {
} else { } else {
assert(globals->type == tp_dict); assert(globals->type == tp_dict);
} }
Frame* frame = Frame__new(co, sp, module, globals, locals, false, true); Frame* frame = Frame__new(co, sp, module, globals, locals, true);
VM__push_frame(vm, frame); VM__push_frame(vm, frame);
FrameResult res = VM__run_top_frame(vm); FrameResult res = VM__run_top_frame(vm);
if(res == RES_ERROR) return false; if(res == RES_ERROR) return false;

View File

@ -511,13 +511,12 @@ void py_newlocals(py_Ref out) {
py_newglobals(out); py_newglobals(out);
return; return;
} }
if(frame->is_locals_proxy) { if(frame->is_locals_special) {
if(frame->locals->type == tp_locals) { switch(frame->locals->type) {
frame = frame->locals->_ptr; case tp_locals: frame = frame->locals->_ptr; break;
} else { case tp_dict: *out = *frame->locals; return;
assert(frame->locals->type == tp_dict); case tp_nil: py_newglobals(out); return;
*out = *frame->locals; default: c11__unreachable();
return;
} }
} }
FastLocals__to_dict(frame->locals, frame->co); FastLocals__to_dict(frame->locals, frame->co);
@ -530,11 +529,8 @@ static void pk_push_locals_proxy() {
py_pushnil(); py_pushnil();
return; return;
} }
if(frame->is_locals_proxy) { if(frame->is_locals_special) {
py_push(frame->locals); py_push(frame->locals);
} else {
if(py_isnil(frame->locals)) {
py_pushnil();
} else { } else {
py_StackRef out = py_pushtmp(); py_StackRef out = py_pushtmp();
out->type = tp_locals; out->type = tp_locals;
@ -544,7 +540,6 @@ static void pk_push_locals_proxy() {
// which will expire when the frame is destroyed // which will expire when the frame is destroyed
out->_ptr = frame; out->_ptr = frame;
} }
}
} }
static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) { static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) {
@ -827,16 +822,14 @@ static bool super__new__(int argc, py_Ref argv) {
py_Ref self_arg = NULL; py_Ref self_arg = NULL;
if(argc == 1) { if(argc == 1) {
// super() // super()
if(frame->is_p0_function && !frame->is_locals_proxy) { if(!frame->is_locals_special) {
py_TValue* callable = frame->p0; py_TValue* callable = frame->p0;
if(callable->type == tp_boundmethod) callable = py_getslot(frame->p0, 1); if(callable->type == tp_boundmethod) callable = py_getslot(frame->p0, 1);
if(callable->type == tp_function) { if(callable->type == tp_function) {
Function* func = py_touserdata(callable); Function* func = py_touserdata(callable);
if(func->clazz != NULL) { if(func->clazz != NULL) {
class_arg = *(py_Type*)PyObject__userdata(func->clazz); class_arg = *(py_Type*)PyObject__userdata(func->clazz);
if(frame->co->nlocals > 0) { if(frame->co->nlocals > 0) { self_arg = &frame->locals[0]; }
if(!frame->is_locals_proxy) self_arg = &frame->locals[0];
}
} }
} }
} }