2024-06-28 23:07:26 +08:00

134 lines
4.3 KiB
C

#include "pocketpy/interpreter/frame.h"
#include "pocketpy/objects/object.h"
void ValueStack__ctor(ValueStack* self) {
self->sp = self->begin;
self->end = self->begin + PK_VM_STACK_SIZE;
}
void ValueStack__clear(ValueStack* self) {
self->sp = self->begin;
}
PyVar* FastLocals__try_get_by_name(PyVar* locals, const CodeObject* co, py_Name name){
int index = c11_smallmap_n2i__get(&co->varnames_inv, name, -1);
if(index == -1) return NULL;
return &locals[index];
}
pk_NameDict* FastLocals__to_namedict(PyVar* locals, const CodeObject* co) {
pk_NameDict* dict = pk_NameDict__new();
c11__foreach(c11_smallmap_n2i_KV, &co->varnames_inv, entry) {
PyVar value = locals[entry->value];
if(!py_isnull(&value)){
pk_NameDict__set(dict, entry->key, value);
}
}
return dict;
}
UnwindTarget* UnwindTarget__new(UnwindTarget* next, int iblock, int offset){
UnwindTarget* self = malloc(sizeof(UnwindTarget));
self->next = next;
self->iblock = iblock;
self->offset = offset;
return self;
}
void UnwindTarget__delete(UnwindTarget* self){
free(self);
}
Frame* Frame__new(const CodeObject* co, const PyVar* module, const PyVar* function, PyVar* p0, PyVar* locals, const CodeObject* locals_co){
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
Frame* self = PoolFrame_alloc();
self->f_back = NULL;
self->ip = (Bytecode*)co->codes.data - 1;
self->co = co;
self->module = module->_obj;
self->function = function->_obj;
self->p0 = p0;
self->locals = locals;
self->locals_co = locals_co;
self->uw_list = NULL;
return self;
}
void Frame__delete(Frame* self){
while(self->uw_list) {
UnwindTarget* p = self->uw_list;
self->uw_list = p->next;
UnwindTarget__delete(p);
}
PoolFrame_dealloc(self);
}
int Frame__prepare_jump_exception_handler(Frame* self, ValueStack* _s){
// try to find a parent try block
int iblock = Frame__iblock(self);
while(iblock >= 0) {
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
if(block->type == CodeBlockType_TRY_EXCEPT) break;
iblock = block->parent;
}
if(iblock < 0) return -1;
PyVar obj = *--_s->sp; // pop exception object
UnwindTarget* uw = Frame__find_unwind_target(self, iblock);
_s->sp = (self->locals + uw->offset); // unwind the stack
*(_s->sp++) = obj; // push it back
return c11__at(CodeBlock, &self->co->blocks, iblock)->end;
}
void Frame__prepare_jump_break(Frame* self, ValueStack* _s, int target){
int iblock = Frame__iblock(self);
if(target >= self->co->codes.count) {
while(iblock >= 0) iblock = Frame__exit_block(self, _s, iblock);
} else {
// BUG (solved)
// for i in range(4):
// _ = 0
// # if there is no op here, the block check will fail
// while i: --i
int next_block = c11__at(BytecodeEx, &self->co->codes_ex, target)->iblock;
while(iblock >= 0 && iblock != next_block)
iblock = Frame__exit_block(self, _s, iblock);
assert(iblock == next_block);
}
}
int Frame__prepare_loop_break(Frame* self, ValueStack* _s){
int iblock = Frame__iblock(self);
int target = c11__getitem(CodeBlock, &self->co->blocks, iblock).end;
Frame__prepare_jump_break(self, _s, target);
return target;
}
int Frame__exit_block(Frame* self, ValueStack* _s, int iblock){
CodeBlock* block = c11__at(CodeBlock, &self->co->blocks, iblock);
if(block->type == CodeBlockType_FOR_LOOP) {
_s->sp--; // pop iterator
} else if(block->type == CodeBlockType_CONTEXT_MANAGER) {
_s->sp--; // pop context variable
}
return block->parent;
}
UnwindTarget* Frame__find_unwind_target(Frame* self, int iblock){
UnwindTarget* uw;
for(uw = self->uw_list; uw; uw = uw->next) {
if(uw->iblock == iblock) return uw;
}
return NULL;
}
void Frame__set_unwind_target(Frame* self, PyVar* sp) {
int iblock = Frame__iblock(self);
UnwindTarget* existing = Frame__find_unwind_target(self, iblock);
if(existing) {
existing->offset = sp - self->locals;
} else {
UnwindTarget* prev = self->uw_list;
self->uw_list = UnwindTarget__new(prev, iblock, sp - self->locals);
}
}