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_GlobalRef module;
py_Ref globals; // a module object or a dict object
py_Ref locals; // locals base or a proxy object (such as dict)
bool is_p0_function;
bool is_locals_proxy;
py_Ref locals;
bool is_locals_special;
int ip;
UnwindTarget* uw_list;
} Frame;
@ -46,8 +45,7 @@ Frame* Frame__new(const CodeObject* co,
py_GlobalRef module,
py_Ref globals,
py_Ref locals,
bool is_p0_function,
bool is_locals_proxy);
bool is_locals_special);
void Frame__delete(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__ctor(ud, decl, frame->module, frame->globals);
if(decl->nested) {
if(frame->is_locals_proxy) {
RuntimeError("cannot create closure from locals proxy");
if(frame->is_locals_special) {
RuntimeError("cannot create closure from special locals");
goto __ERROR;
}
ud->closure = FastLocals__to_namedict(frame->locals, frame->co);
@ -198,7 +198,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
/*****************************************/
case OP_LOAD_FAST: {
assert(!frame->is_locals_proxy);
assert(!frame->is_locals_special);
PUSH(&frame->locals[byte.arg]);
if(py_isnil(TOP())) {
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;
}
case OP_STORE_FAST: {
assert(!frame->is_locals_proxy);
assert(!frame->is_locals_special);
frame->locals[byte.arg] = POPX();
DISPATCH();
}
@ -392,7 +392,7 @@ FrameResult VM__run_top_frame(VM* self) {
goto __ERROR;
}
case OP_DELETE_FAST: {
assert(!frame->is_locals_proxy);
assert(!frame->is_locals_special);
py_Ref tmp = &frame->locals[byte.arg];
if(py_isnil(tmp)) {
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,
frame->co->src,
Frame__lineno(frame),
frame->is_p0_function ? frame->co->name->data : NULL);
!frame->is_locals_special ? frame->co->name->data : NULL);
__ERROR_RE_RAISE:
do {
} while(0);

View File

@ -52,11 +52,12 @@ Frame* Frame__new(const CodeObject* co,
py_GlobalRef module,
py_Ref globals,
py_Ref locals,
bool is_p0_function,
bool is_locals_proxy) {
bool is_locals_special) {
assert(module->type == tp_module);
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);
self->f_back = NULL;
self->co = co;
@ -64,8 +65,7 @@ Frame* Frame__new(const CodeObject* co,
self->module = module;
self->globals = globals;
self->locals = locals;
self->is_p0_function = is_p0_function;
self->is_locals_proxy = is_locals_proxy;
self->is_locals_special = is_locals_special;
self->ip = -1;
self->uw_list = NULL;
return self;
@ -81,8 +81,7 @@ void Frame__delete(Frame* self) {
}
py_StackRef Frame__locals_sp(Frame* self) {
if(!self->is_locals_proxy) { return self->locals; }
return self->p0;
return !self->is_locals_special ? self->locals : self->p0;
}
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) {
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);
}
@ -166,12 +165,12 @@ int Frame__delglobal(Frame* self, py_Name name) {
}
int Frame__getlocal(Frame* self, py_Name name) {
if(self->is_locals_proxy) {
if(self->locals->type == tp_locals) {
self = self->locals->_ptr;
} else {
assert(self->locals->type == tp_dict);
return py_dict_getitem(self->locals, py_name2ref(name));
if(self->is_locals_special) {
switch(self->locals->type) {
case tp_locals: self = self->locals->_ptr; break;
case tp_dict: return py_dict_getitem(self->locals, py_name2ref(name));
case tp_nil: return 0;
default: c11__unreachable();
}
}
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) {
if(self->is_locals_proxy) {
if(self->locals->type == tp_locals) {
self = self->locals->_ptr;
} else {
assert(self->locals->type == tp_dict);
return py_dict_setitem(self->locals, py_name2ref(name), val);
if(self->is_locals_special) {
switch(self->locals->type) {
case tp_locals: self = self->locals->_ptr; break;
case tp_dict: return py_dict_setitem(self->locals, py_name2ref(name), val);
case tp_nil: return false;
default: c11__unreachable();
}
}
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) {
if(self->is_locals_proxy) {
if(self->locals->type == tp_locals) {
self = self->locals->_ptr;
} else {
assert(self->locals->type == tp_dict);
return py_dict_delitem(self->locals, py_name2ref(name));
if(self->is_locals_special) {
switch(self->locals->type) {
case tp_locals: self = self->locals->_ptr; break;
case tp_dict: return py_dict_delitem(self->locals, py_name2ref(name));
case tp_nil: return 0;
default: c11__unreachable();
}
}
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) {
assert(!self->is_locals_proxy);
assert(!self->is_locals_special);
int index = c11_smallmap_n2i__get(&self->co->varnames_inv, name, -1);
if(index == -1) return NULL;
return &self->locals[index];
}
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);
if(ud->closure == NULL) return NULL;
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();
// reset frame->p0
if(ud->frame->is_locals_proxy){
return RuntimeError("cannot resume generator with locals proxy");
}
assert(!ud->frame->is_locals_special);
int locals_offset = ud->frame->locals - ud->frame->p0;
ud->frame->p0 = py_peek(0);
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
if(!fn->cfunc) {
// python function
VM__push_frame(self,
Frame__new(co, p0, fn->module, fn->globals, argv, true, false));
VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
return opcall ? RES_CALL : VM__run_top_frame(self);
} else {
// decl-based binding
@ -515,8 +514,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
// submit the call
if(!fn->cfunc) {
// python function
VM__push_frame(self,
Frame__new(co, p0, fn->module, fn->globals, argv, true, false));
VM__push_frame(self, Frame__new(co, p0, fn->module, fn->globals, argv, false));
return opcall ? RES_CALL : VM__run_top_frame(self);
} else {
// 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
self->stack.sp = argv + co->nlocals;
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);
self->stack.sp = p0; // reset the stack
return RES_RETURN;

View File

@ -54,7 +54,7 @@ bool pk_exec(CodeObject* co, py_Ref module) {
assert(module->type == tp_module);
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);
FrameResult res = VM__run_top_frame(vm);
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 {
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);
FrameResult res = VM__run_top_frame(vm);
if(res == RES_ERROR) return false;

View File

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