This commit is contained in:
blueloveTH 2025-02-25 19:30:46 +08:00
parent 2d5561441d
commit 9af9d228dd
7 changed files with 135 additions and 26 deletions

View File

@ -57,10 +57,14 @@ int Frame__getglobal(Frame* self, py_Name name) PY_RAISE PY_RETURN;
bool Frame__setglobal(Frame* self, py_Name name, py_TValue* val) PY_RAISE;
int Frame__delglobal(Frame* self, py_Name name) PY_RAISE;
py_Ref Frame__getclosure(Frame* self, py_Name name);
int Frame__getlocal(Frame* self, py_Name name) PY_RAISE PY_RETURN;
int Frame__setlocal(Frame* self, py_Name name, py_TValue* val) PY_RAISE;
int Frame__dellocal(Frame* self, py_Name name) PY_RAISE;
py_Ref Frame__getclosure(Frame* self, py_Name name);
py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name);
py_StackRef Frame__locals_sp(Frame* self);
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack*);

View File

@ -96,6 +96,7 @@ bool pk_loadmethod(py_StackRef self, py_Name name);
bool pk_callmagic(py_Name name, int argc, py_Ref argv);
bool pk_exec(CodeObject* co, py_Ref module);
bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals);
/// Assumes [a, b] are on the stack, performs a binary op.
/// The result is stored in `self->last_retval`.

View File

@ -194,6 +194,7 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
/*****************************************/
case OP_LOAD_FAST: {
assert(!frame->is_locals_proxy);
PUSH(&frame->locals[byte.arg]);
if(py_isnil(TOP())) {
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
@ -220,7 +221,6 @@ FrameResult VM__run_top_frame(VM* self) {
}
}
}
// `LOAD_
// globals
if(py_getitem(&frame->p0[0], TOP())) {
py_assign(TOP(), py_retval());
@ -343,7 +343,11 @@ FrameResult VM__run_top_frame(VM* self) {
TypeError("'%t' object is not subscriptable", SECOND()->type);
goto __ERROR;
}
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
case OP_STORE_FAST: {
assert(!frame->is_locals_proxy);
frame->locals[byte.arg] = POPX();
DISPATCH();
}
case OP_STORE_NAME: {
// assert(frame->is_dynamic);
py_Name name = byte.arg;
@ -405,6 +409,7 @@ FrameResult VM__run_top_frame(VM* self) {
goto __ERROR;
}
case OP_DELETE_FAST: {
assert(!frame->is_locals_proxy);
py_Ref tmp = &frame->locals[byte.arg];
if(py_isnil(tmp)) {
py_Name name = c11__getitem(py_Name, &frame->co->varnames, byte.arg);

View File

@ -79,7 +79,7 @@ int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s) {
}
if(iblock < 0) return -1;
UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
_s->sp = (self->locals + uw->offset); // unwind the stack
_s->sp = (Frame__locals_sp(self) + uw->offset); // unwind the stack
return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
}
@ -95,10 +95,10 @@ void Frame__set_unwind_target(Frame* self, py_TValue* sp) {
int iblock = Frame__iblock(self);
UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
if(existing) {
existing->offset = sp - self->locals;
existing->offset = sp - Frame__locals_sp(self);
} else {
UnwindTarget* prev = self->uw_list;
self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals);
self->uw_list = UnwindTarget__new(prev, iblock, sp - Frame__locals_sp(self));
}
}
@ -149,6 +149,77 @@ int Frame__delglobal(Frame* self, py_Name name) {
}
}
int Frame__getlocal(Frame* self, py_Name name) {
if(self->is_locals_proxy) {
py_StackRef p0 = py_peek(0);
py_push(self->locals);
py_pushmethod(__getitem__);
py_push(py_name2ref(name));
bool ok = py_vectorcall(1, 0);
if(!ok) {
if(py_matchexc(tp_KeyError)) {
py_clearexc(p0);
return 0;
}
return -1;
}
return 1;
} else {
py_Ref slot = Frame__getlocal_noproxy(self, name);
if(slot == NULL) return 0; // bad slot
if(py_isnil(slot)) {
UnboundLocalError(name);
return -1;
}
py_assign(py_retval(), slot);
return 1;
}
}
int Frame__setlocal(Frame* self, py_Name name, py_TValue* val) {
if(self->is_locals_proxy) {
py_push(self->locals);
py_pushmethod(__setitem__);
py_push(py_name2ref(name));
py_push(val);
bool ok = py_vectorcall(2, 0);
if(!ok) return -1;
return 1;
} else {
py_Ref slot = Frame__getlocal_noproxy(self, name);
if(slot == NULL) return 0; // bad slot
*slot = *val;
return 1;
}
}
int Frame__dellocal(Frame* self, py_Name name) {
if(self->is_locals_proxy) {
py_StackRef p0 = py_peek(0);
py_push(self->locals);
py_pushmethod(__delitem__);
py_push(py_name2ref(name));
bool ok = py_vectorcall(1, 0);
if(!ok) {
if(py_matchexc(tp_KeyError)) {
py_clearexc(p0);
return 0;
}
return -1;
}
return 1;
} else {
py_Ref slot = Frame__getlocal_noproxy(self, name);
if(slot == NULL) return 0; // bad slot
if(py_isnil(slot)) {
UnboundLocalError(name);
return -1;
}
py_newnil(slot);
return 1;
}
}
py_StackRef Frame__getlocal_noproxy(Frame* self, py_Name name) {
assert(!self->is_locals_proxy);
return FastLocals__try_get_by_name(self->locals, self->co, name);

View File

@ -28,10 +28,14 @@ static bool generator__next__(int argc, py_Ref argv) {
if(ud->state == 2) return StopIteration();
// reset frame->p0
int locals_offset = ud->frame->locals - ud->frame->p0;
ud->frame->p0 = py_peek(0);
ud->frame->locals = ud->frame->p0 + locals_offset;
if(!ud->frame->is_locals_proxy){
int locals_offset = ud->frame->locals - ud->frame->p0;
ud->frame->p0 = py_peek(0);
ud->frame->locals = ud->frame->p0 + locals_offset;
}else{
ud->frame->p0 = py_peek(0);
}
// restore the context
py_Ref backup = py_getslot(argv, 0);
int length = py_list_len(backup);

View File

@ -7,12 +7,11 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/compiler/compiler.h"
static void code__gc_mark(void* ud) { CodeObject__gc_mark(ud); }
#include <assert.h>
py_Type pk_code__register() {
py_Type type = pk_newtype("code", tp_object, NULL, (py_Dtor)CodeObject__dtor, false, true);
pk__tp_set_marker(type, code__gc_mark);
pk__tp_set_marker(type, (void (*)(void *))CodeObject__gc_mark);
return type;
}
@ -57,16 +56,34 @@ bool pk_exec(CodeObject* co, py_Ref module) {
assert(module->type == tp_module);
py_StackRef sp = vm->stack.sp;
if(co->src->is_dynamic) sp -= 3; // [globals, locals, code]
const bool is_p0_function = false;
const bool is_locals_proxy = true;
Frame* frame = Frame__new(co, sp, module, module, sp, is_p0_function, is_locals_proxy);
Frame* frame = Frame__new(co, sp, module, module, sp, false, false);
VM__push_frame(vm, frame);
FrameResult res = VM__run_top_frame(vm);
if(res == RES_ERROR) return false;
if(res == RES_RETURN) return true;
c11__unreachable();
assert(res == RES_RETURN);
return true;
}
bool pk_execdyn(CodeObject* co, py_Ref module, py_Ref globals, py_Ref locals) {
VM* vm = pk_current_vm;
if(!module) module = &vm->main;
assert(module->type == tp_module);
py_StackRef sp = vm->stack.sp;
assert(globals != NULL && locals != NULL);
if(globals->type == tp_namedict) {
globals = py_getslot(globals, 0);
assert(globals->type == tp_module);
} else {
assert(globals->type == tp_dict);
}
Frame* frame = Frame__new(co, sp, module, globals, locals, false, true);
VM__push_frame(vm, frame);
FrameResult res = VM__run_top_frame(vm);
if(res == RES_ERROR) return false;
assert(res == RES_RETURN);
return true;
}
bool py_exec(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {

View File

@ -501,7 +501,7 @@ void py_newglobals(py_Ref out) {
if(frame->globals->type == tp_module) {
pk_mappingproxy__namedict(out, frame->globals);
} else {
*out = *frame->globals; // dict
*out = *frame->globals; // dict
}
}
@ -511,9 +511,9 @@ void py_newlocals(py_Ref out) {
py_newglobals(out);
return;
}
if(!frame->is_locals_proxy){
if(!frame->is_locals_proxy) {
pk_mappingproxy__locals(out, frame);
}else{
} else {
*out = *frame->locals;
}
}
@ -529,6 +529,7 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
if(py_isnone(py_arg(1))) {
py_newglobals(py_pushtmp());
} else {
if(!py_checktype(py_arg(1), tp_dict)) return false;
py_push(py_arg(1));
}
py_pushnone();
@ -538,6 +539,7 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
if(py_isnone(py_arg(1))) {
py_newglobals(py_pushtmp());
} else {
if(!py_checktype(py_arg(1), tp_dict)) return false;
py_push(py_arg(1));
}
py_push(py_arg(2));
@ -562,12 +564,15 @@ static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_
// [globals, locals, code]
CodeObject* co = py_touserdata(code);
if(!co->src->is_dynamic) {
py_shrink(3);
if(argc != 1)
return ValueError("code object is not dynamic, `globals` and `locals` must be None");
py_shrink(3);
}
Frame* frame = pk_current_vm->top_frame;
return pk_exec(co, frame ? frame->module : NULL);
bool ok = pk_execdyn(co, frame ? frame->module : NULL, py_peek(-3), py_peek(-2));
py_shrink(3);
return ok;
}
static bool builtins_exec(int argc, py_Ref argv) {
@ -787,7 +792,9 @@ static bool super__new__(int argc, py_Ref argv) {
Function* func = py_touserdata(callable);
if(func->clazz != NULL) {
class_arg = *(py_Type*)PyObject__userdata(func->clazz);
if(frame->co->nlocals > 0) self_arg = &frame->locals[0];
if(frame->co->nlocals > 0) {
if(!frame->is_locals_proxy) self_arg = &frame->locals[0];
}
}
}
}