This commit is contained in:
blueloveTH 2025-02-25 16:45:32 +08:00
parent 5a72730853
commit 2d5561441d
9 changed files with 115 additions and 104 deletions

View File

@ -1,7 +0,0 @@
#pragma once
#include <stdint.h>
#include "pocketpy/common/str.h"
void py_Name__initialize();
void py_Name__finalize();

View File

@ -4,7 +4,6 @@
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/namedict.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/common/strname.h"
#include "pocketpy/pocketpy.h"
py_TValue* FastLocals__try_get_by_name(py_TValue* locals, const CodeObject* co, py_Name name);

View File

@ -0,0 +1,18 @@
#pragma once
#include "pocketpy/objects/base.h"
#include "pocketpy/common/smallmap.h"
typedef struct {
char* data; // null-terminated data
int size; // size of the data excluding the null-terminator
py_TValue obj; // cached `str` object (lazy initialized)
} RInternedEntry;
typedef struct {
c11_smallmap_s2n interned;
c11_vector /* T=RInternedEntry */ r_interned;
} InternedNames;
void InternedNames__ctor(InternedNames* self);
void InternedNames__dtor(InternedNames* self);

View File

@ -7,6 +7,7 @@
#include "pocketpy/interpreter/frame.h"
#include "pocketpy/interpreter/modules.h"
#include "pocketpy/interpreter/typeinfo.h"
#include "pocketpy/interpreter/name.h"
// TODO:
// 1. __eq__ and __ne__ fallbacks
@ -41,6 +42,7 @@ typedef struct VM {
py_StackRef __curr_function;
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
InternedNames names;
FixedMemoryPool pool_frame;
ManagedHeap heap;
ValueStack stack; // put `stack` at the end for better cache locality

View File

@ -1,10 +1,6 @@
#pragma once
#include "pocketpy/common/str.h"
#include "pocketpy/common/strname.h"
#include "pocketpy/objects/codeobject.h"
#include "pocketpy/objects/sourcedata.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/pocketpy.h"
typedef struct{

View File

@ -1,83 +0,0 @@
#include "pocketpy/common/strname.h"
#include "pocketpy/common/smallmap.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/common/vector.h"
#include "pocketpy/pocketpy.h"
#include <stdio.h>
typedef struct {
char* data; // null-terminated data
int size; // size of the data excluding the null-terminator
py_TValue* ref; // cached `str` object (lazy initialized)
} RInternedEntry;
// TODO: use a more efficient data structure
static c11_smallmap_s2n _interned;
static c11_vector /* T=RInternedEntry */ _r_interned;
void py_Name__initialize() {
c11_smallmap_s2n__ctor(&_interned);
c11_vector__ctor(&_r_interned, sizeof(RInternedEntry));
#define MAGIC_METHOD(x) \
if(x != py_name(#x)) abort();
#include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD
}
void py_Name__finalize() {
// free all char*
for(int i = 0; i < _r_interned.length; i++) {
PK_FREE(c11__getitem(RInternedEntry, &_r_interned, i).data);
}
c11_smallmap_s2n__dtor(&_interned);
c11_vector__dtor(&_r_interned);
}
py_Name py_name(const char* name) { return py_namev((c11_sv){name, strlen(name)}); }
py_Name py_namev(c11_sv name) {
uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0);
if(index != 0) return index;
// generate new index
if(_interned.length > 65530) c11__abort("py_Name index overflow");
// NOTE: we must allocate the string in the heap so iterators are not invalidated
char* p = PK_MALLOC(name.size + 1);
memcpy(p, name.data, name.size);
p[name.size] = '\0';
RInternedEntry entry;
entry.data = p;
entry.size = name.size;
entry.ref = NULL;
c11_vector__push(RInternedEntry, &_r_interned, entry);
index = _r_interned.length; // 1-based
// save to _interned
c11_smallmap_s2n__set(&_interned, (c11_sv){p, name.size}, index);
assert(_interned.length == _r_interned.length);
return index;
}
const char* py_name2str(py_Name index) {
assert(index > 0 && index <= _interned.length);
return c11__getitem(RInternedEntry, &_r_interned, index - 1).data;
}
c11_sv py_name2sv(py_Name index) {
assert(index > 0 && index <= _interned.length);
RInternedEntry entry = c11__getitem(RInternedEntry, &_r_interned, index - 1);
return (c11_sv){entry.data, entry.size};
}
py_GlobalRef py_name2ref(py_Name index) {
assert(index > 0 && index <= _interned.length);
RInternedEntry entry = c11__getitem(RInternedEntry, &_r_interned, index - 1);
if(entry.ref == NULL){
entry.ref = PK_MALLOC(16); // ...
c11_sv sv;
sv.data = entry.data;
sv.size = entry.size;
py_newstrv(entry.ref, sv);
}
return entry.ref;
}

77
src/interpreter/name.c Normal file
View File

@ -0,0 +1,77 @@
#include "pocketpy/interpreter/name.h"
#include "pocketpy/interpreter/vm.h"
void InternedNames__ctor(InternedNames* self) {
c11_smallmap_s2n__ctor(&self->interned);
c11_vector__ctor(&self->r_interned, sizeof(RInternedEntry));
// initialize all magic names
#define MAGIC_METHOD(x) \
if(x != py_name(#x)) abort();
#include "pocketpy/xmacros/magics.h"
#undef MAGIC_METHOD
}
void InternedNames__dtor(InternedNames* self) {
for(int i = 0; i < self->r_interned.length; i++) {
PK_FREE(c11__getitem(RInternedEntry, &self->r_interned, i).data);
}
c11_smallmap_s2n__dtor(&self->interned);
c11_vector__dtor(&self->r_interned);
}
py_Name py_name(const char* name) {
c11_sv sv;
sv.data = name;
sv.size = strlen(name);
return py_namev(sv);
}
py_Name py_namev(c11_sv name) {
InternedNames* self = &pk_current_vm->names;
uint16_t index = c11_smallmap_s2n__get(&self->interned, name, 0);
if(index != 0) return index;
// generate new index
if(self->interned.length > 65530) c11__abort("py_Name index overflow");
// NOTE: we must allocate the string in the heap so iterators are not invalidated
char* p = PK_MALLOC(name.size + 1);
memcpy(p, name.data, name.size);
p[name.size] = '\0';
RInternedEntry entry;
entry.data = p;
entry.size = name.size;
entry.obj.type = tp_nil;
c11_vector__push(RInternedEntry, &self->r_interned, entry);
index = self->r_interned.length; // 1-based
// save to _interned
c11_smallmap_s2n__set(&self->interned, (c11_sv){p, name.size}, index);
assert(self->interned.length == self->r_interned.length);
return index;
}
const char* py_name2str(py_Name index) {
InternedNames* self = &pk_current_vm->names;
assert(index > 0 && index <= self->interned.length);
return c11__getitem(RInternedEntry, &self->r_interned, index - 1).data;
}
c11_sv py_name2sv(py_Name index) {
InternedNames* self = &pk_current_vm->names;
assert(index > 0 && index <= self->interned.length);
RInternedEntry entry = c11__getitem(RInternedEntry, &self->r_interned, index - 1);
return (c11_sv){entry.data, entry.size};
}
py_GlobalRef py_name2ref(py_Name index) {
InternedNames* self = &pk_current_vm->names;
assert(index > 0 && index <= self->interned.length);
RInternedEntry* entry = c11__at(RInternedEntry, &self->r_interned, index - 1);
if(entry->obj.type == tp_nil){
c11_sv sv;
sv.data = entry->data;
sv.size = entry->size;
py_newstrv(&entry->obj, sv);
}
return &entry->obj;
}

View File

@ -57,6 +57,7 @@ static void py_TypeInfo__ctor(py_TypeInfo* self,
void VM__ctor(VM* self) {
self->top_frame = NULL;
InternedNames__ctor(&self->names);
ModuleDict__ctor(&self->modules, NULL, *py_NIL());
TypeList__ctor(&self->types);
@ -258,6 +259,7 @@ void VM__dtor(VM* self) {
TypeList__dtor(&self->types);
FixedMemoryPool__dtor(&self->pool_frame);
ValueStack__clear(&self->stack);
InternedNames__dtor(&self->names);
}
void VM__push_frame(VM* self, Frame* frame) {
@ -281,7 +283,11 @@ static void _clip_int(int* value, int min, int max) {
if(*value > max) *value = max;
}
bool pk__parse_int_slice(py_Ref slice, int length, int* restrict start, int* restrict stop, int* restrict step) {
bool pk__parse_int_slice(py_Ref slice,
int length,
int* restrict start,
int* restrict stop,
int* restrict step) {
if(py_isint(slice)) {
int index = py_toint(slice);
bool ok = pk__normalize_index(&index, length);
@ -431,9 +437,8 @@ static bool
co->name->data);
} else {
// add to **kwargs
bool ok = py_dict_setitem(&buffer[decl->starred_kwarg],
py_name2ref(key),
&p1[2 * j + 1]);
bool ok =
py_dict_setitem(&buffer[decl->starred_kwarg], py_name2ref(key), &p1[2 * j + 1]);
if(!ok) return false;
}
}
@ -480,7 +485,8 @@ 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, true, false));
return opcall ? RES_CALL : VM__run_top_frame(self);
} else {
// decl-based binding
@ -509,7 +515,8 @@ 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, true, false));
return opcall ? RES_CALL : VM__run_top_frame(self);
} else {
// decl-based binding
@ -693,6 +700,11 @@ void ManagedHeap__mark(ManagedHeap* self) {
for(int i = 0; i < c11__count_array(vm->reg); i++) {
pk__mark_value(&vm->reg[i]);
}
// mark interned names
for(int i = 0; i < vm->names.r_interned.length; i++) {
RInternedEntry* entry = c11__at(RInternedEntry, &vm->names.r_interned, i);
pk__mark_value(&entry->obj);
}
}
void pk_print_stack(VM* self, Frame* frame, Bytecode byte) {

View File

@ -27,8 +27,6 @@ void py_initialize() {
static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
static_assert(offsetof(py_TValue, extra) == 4, "offsetof(py_TValue, extra) != 4");
py_Name__initialize();
pk_current_vm = pk_all_vm[0] = &pk_default_vm;
// initialize some convenient references
@ -61,7 +59,6 @@ void py_finalize() {
pk_current_vm = &pk_default_vm;
VM__dtor(&pk_default_vm);
pk_current_vm = NULL;
py_Name__finalize();
}
void py_switchvm(int index) {