mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-08 20:50:16 +00:00
Compare commits
11 Commits
b4b9651373
...
46f9e4ed4f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46f9e4ed4f | ||
|
|
19d0cfd4fd | ||
|
|
7b4994ee35 | ||
|
|
bd36a53226 | ||
|
|
854f0d9b35 | ||
|
|
2572ddd982 | ||
|
|
b3084a5c87 | ||
|
|
160bc99d04 | ||
|
|
2fdf09f652 | ||
|
|
0ba04d18d7 | ||
|
|
2061f90a27 |
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_linux:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@ -58,8 +58,6 @@ jobs:
|
||||
with:
|
||||
version: 15
|
||||
platform: x64
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y libclang-rt-15-dev
|
||||
- name: Unit Test with Coverage
|
||||
run: bash run_tests.sh
|
||||
- name: Upload coverage reports to Codecov
|
||||
|
||||
@ -9,7 +9,7 @@ typedef struct FixedMemoryPool {
|
||||
int exceeded_bytes;
|
||||
|
||||
char** _free_list;
|
||||
char** _free_list_end;
|
||||
int _free_list_length;
|
||||
} FixedMemoryPool;
|
||||
|
||||
void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount);
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#define PK_VERSION "2.0.6"
|
||||
#define PK_VERSION "2.0.7"
|
||||
#define PK_VERSION_MAJOR 2
|
||||
#define PK_VERSION_MINOR 0
|
||||
#define PK_VERSION_PATCH 6
|
||||
#define PK_VERSION_PATCH 7
|
||||
|
||||
/*************** feature settings ***************/
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#if PK_LOW_MEMORY_MODE
|
||||
#define PK_GC_MIN_THRESHOLD 2048
|
||||
#else
|
||||
#define PK_GC_MIN_THRESHOLD 16384
|
||||
#define PK_GC_MIN_THRESHOLD 32768
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ typedef struct py_TypeInfo {
|
||||
py_TValue annotations; // type annotations
|
||||
|
||||
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
|
||||
void (*gc_mark)(void* ud);
|
||||
|
||||
/* Magic Slots */
|
||||
py_TValue magic_0[PK_MAGIC_SLOTS_COMMON_LENGTH]; // common magic slots
|
||||
@ -41,6 +40,6 @@ py_TypeInfo* TypeList__get(TypeList* self, py_Type index);
|
||||
py_TypeInfo* TypeList__emplace(TypeList* self);
|
||||
void TypeList__apply(TypeList* self, void (*f)(py_TypeInfo*, void*), void* ctx);
|
||||
py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index);
|
||||
py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index);
|
||||
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index);
|
||||
|
||||
#define TypeList__magic_common(ti, index) ((ti)->magic_0 + ((index)-PK_MAGIC_SLOTS_UNCOMMON_LENGTH))
|
||||
|
||||
28
include/pocketpy/interpreter/types.h
Normal file
28
include/pocketpy/interpreter/types.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "pocketpy/common/vector.h"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
#define PK_DICT_MAX_COLLISION 4
|
||||
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
py_TValue key;
|
||||
py_TValue val;
|
||||
} DictEntry;
|
||||
|
||||
typedef struct {
|
||||
int _[PK_DICT_MAX_COLLISION];
|
||||
} DictIndex;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
uint32_t capacity;
|
||||
DictIndex* indices;
|
||||
c11_vector /*T=DictEntry*/ entries;
|
||||
} Dict;
|
||||
|
||||
typedef c11_vector List;
|
||||
|
||||
void c11_chunked_array2d__mark(void* ud);
|
||||
void function__gc_mark(void* ud);
|
||||
@ -8,6 +8,7 @@
|
||||
#include "pocketpy/interpreter/modules.h"
|
||||
#include "pocketpy/interpreter/typeinfo.h"
|
||||
#include "pocketpy/interpreter/name.h"
|
||||
#include "pocketpy/interpreter/types.h"
|
||||
|
||||
// TODO:
|
||||
// 1. __eq__ and __ne__ fallbacks
|
||||
@ -32,7 +33,6 @@ typedef struct VM {
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
volatile bool is_signal_interrupted;
|
||||
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
@ -58,8 +58,7 @@ bool pk__parse_int_slice(py_Ref slice, int length, int* restrict start, int* res
|
||||
bool pk__normalize_index(int* index, int length);
|
||||
|
||||
#define pk__mark_value(val) if((val)->is_ptr && !(val)->_obj->gc_marked) PyObject__mark((val)->_obj)
|
||||
void pk__mark_namedict(NameDict*);
|
||||
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*));
|
||||
|
||||
bool pk__object_new(int argc, py_Ref argv);
|
||||
py_TypeInfo* pk__type_info(py_Type type);
|
||||
|
||||
|
||||
@ -34,6 +34,33 @@ typedef struct c11_sv {
|
||||
int size;
|
||||
} c11_sv;
|
||||
|
||||
// An enum for tracing events.
|
||||
enum py_TraceEvent {
|
||||
TraceEvent_Line,
|
||||
TraceEvent_Call,
|
||||
TraceEvent_Return,
|
||||
TraceEvent_Exception,
|
||||
};
|
||||
|
||||
/// A struct contains the arguments of the tracing event.
|
||||
union py_TraceEventArg {
|
||||
struct {
|
||||
int _;
|
||||
} line;
|
||||
|
||||
struct {
|
||||
int _;
|
||||
} call;
|
||||
|
||||
struct {
|
||||
int _;
|
||||
} return_;
|
||||
|
||||
struct {
|
||||
int _;
|
||||
} exception;
|
||||
};
|
||||
|
||||
/// A struct contains the callbacks of the VM.
|
||||
typedef struct py_Callbacks {
|
||||
/// Used by `__import__` to load source code of a module.
|
||||
@ -42,6 +69,8 @@ typedef struct py_Callbacks {
|
||||
void (*print)(const char*);
|
||||
/// Used by `input` to get a character.
|
||||
int (*getchar)();
|
||||
/// C-style `sys.settrace` function.
|
||||
void (*tracefunc)(enum py_TraceEvent, union py_TraceEventArg);
|
||||
} py_Callbacks;
|
||||
|
||||
#define PY_RAISE
|
||||
@ -89,8 +118,6 @@ PK_API void py_resetvm();
|
||||
PK_API void* py_getvmctx();
|
||||
/// Set the current VM context. This is used for user-defined data.
|
||||
PK_API void py_setvmctx(void* ctx);
|
||||
/// Interrupt the current VM and raise a `KeyboardInterrupt` exception.
|
||||
PK_API void py_interrupt();
|
||||
/// Set `sys.argv`. Used for storing command-line arguments.
|
||||
PK_API void py_sys_setargv(int argc, char** argv);
|
||||
/// Setup the callbacks for the current VM.
|
||||
@ -103,9 +130,9 @@ PK_API py_Callbacks* py_callbacks();
|
||||
/// @param module target module. Use NULL for the main module.
|
||||
/// @return `true` if the execution is successful or `false` if an exception is raised.
|
||||
PK_API bool py_exec(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module) PY_RAISE PY_RETURN;
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
py_Ref module) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Evaluate a source string. Equivalent to `py_exec(source, "<string>", EVAL_MODE, module)`.
|
||||
PK_API bool py_eval(const char* source, py_Ref module) PY_RAISE PY_RETURN;
|
||||
@ -128,9 +155,9 @@ PK_API bool py_smarteval(const char* source, py_Ref module, ...) PY_RAISE PY_RET
|
||||
/// Compile a source string into a code object.
|
||||
/// Use python's `exec()` or `eval()` to execute it.
|
||||
PK_API bool py_compile(const char* source,
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||
const char* filename,
|
||||
enum py_CompileMode mode,
|
||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Python equivalent to `globals()`.
|
||||
PK_API void py_newglobals(py_OutRef);
|
||||
@ -190,10 +217,10 @@ PK_API void py_newslice(py_OutRef);
|
||||
PK_API void py_newnativefunc(py_OutRef, py_CFunction);
|
||||
/// Create a `function` object.
|
||||
PK_API py_Name py_newfunction(py_OutRef out,
|
||||
const char* sig,
|
||||
py_CFunction f,
|
||||
const char* docstring,
|
||||
int slots);
|
||||
const char* sig,
|
||||
py_CFunction f,
|
||||
const char* docstring,
|
||||
int slots);
|
||||
/// Create a `boundmethod` object.
|
||||
PK_API void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func);
|
||||
|
||||
@ -219,10 +246,7 @@ PK_API c11_sv py_name2sv(py_Name);
|
||||
/// @param base base type.
|
||||
/// @param module module where the type is defined. Use `NULL` for built-in types.
|
||||
/// @param dtor destructor function. Use `NULL` if not needed.
|
||||
PK_API py_Type py_newtype(const char* name,
|
||||
py_Type base,
|
||||
const py_GlobalRef module,
|
||||
py_Dtor dtor);
|
||||
PK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);
|
||||
|
||||
/// Create a new object.
|
||||
/// @param out output reference.
|
||||
@ -478,11 +502,10 @@ PK_API py_StackRef py_pushtmp();
|
||||
/// If return false: `[self] -> [self]` (no change).
|
||||
PK_API bool py_pushmethod(py_Name name);
|
||||
/// Call a callable object via pocketpy's calling convention.
|
||||
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`
|
||||
/// `argc` is the number of positional arguments excluding `self`.
|
||||
/// `kwargc` is the number of keyword arguments, i.e. the number of key-value pairs.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2,
|
||||
/// v2, ...` `argc` is the number of positional arguments excluding `self`. `kwargc` is the number
|
||||
/// of keyword arguments, i.e. the number of key-value pairs. The result will be set to
|
||||
/// `py_retval()`. The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
|
||||
/// Evaluate an expression and push the result to the stack.
|
||||
/// This function is used for testing.
|
||||
@ -536,7 +559,9 @@ PK_API void py_clearexc(py_StackRef p0);
|
||||
#define AttributeError(self, n) \
|
||||
py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception(tp_UnboundLocalError, "cannot access local variable '%n' where it is not associated with a value", (n))
|
||||
py_exception(tp_UnboundLocalError, \
|
||||
"cannot access local variable '%n' where it is not associated with a value", \
|
||||
(n))
|
||||
|
||||
PK_API bool StopIteration() PY_RAISE;
|
||||
PK_API bool KeyError(py_Ref key) PY_RAISE;
|
||||
@ -672,15 +697,15 @@ PK_API int py_replinput(char* buf, int max_size);
|
||||
/// %t: py_Type
|
||||
/// %n: py_Name
|
||||
|
||||
enum py_MagicNames {
|
||||
py_MagicNames__NULL, // 0 is reserved
|
||||
enum py_MagicName {
|
||||
py_MagicName__NULL, // 0 is reserved
|
||||
|
||||
#define MAGIC_METHOD(x) x,
|
||||
#include "pocketpy/xmacros/magics.h"
|
||||
#undef MAGIC_METHOD
|
||||
};
|
||||
|
||||
enum py_PredefinedTypes {
|
||||
enum py_PredefinedType {
|
||||
tp_nil = 0,
|
||||
tp_object = 1,
|
||||
tp_type, // py_Type
|
||||
|
||||
@ -31,7 +31,7 @@ public:
|
||||
info.name = name;
|
||||
|
||||
py_newfunction(
|
||||
py_tpgetmagic(this->index(), py_MagicNames::__new__),
|
||||
py_tpgetmagic(this->index(), __new__),
|
||||
"__new__(type, *args, **kwargs)",
|
||||
[](int, py_Ref stack) {
|
||||
auto cls = py_offset(stack, 0);
|
||||
|
||||
@ -11,7 +11,7 @@ void FixedMemoryPool__ctor(FixedMemoryPool* self, int BlockSize, int BlockCount)
|
||||
self->data = PK_MALLOC(BlockSize * BlockCount);
|
||||
self->data_end = self->data + BlockSize * BlockCount;
|
||||
self->_free_list = PK_MALLOC(sizeof(void*) * BlockCount);
|
||||
self->_free_list_end = self->_free_list;
|
||||
self->_free_list_length = BlockCount;
|
||||
for(int i = 0; i < BlockCount; i++) {
|
||||
self->_free_list[i] = self->data + i * BlockSize;
|
||||
}
|
||||
@ -23,9 +23,9 @@ void FixedMemoryPool__dtor(FixedMemoryPool* self) {
|
||||
}
|
||||
|
||||
void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
|
||||
if(self->_free_list_end != self->_free_list) {
|
||||
self->_free_list_end--;
|
||||
return *self->_free_list_end;
|
||||
if(self->_free_list_length > 0) {
|
||||
self->_free_list_length--;
|
||||
return self->_free_list[self->_free_list_length];
|
||||
} else {
|
||||
self->exceeded_bytes += self->BlockSize;
|
||||
return PK_MALLOC(self->BlockSize);
|
||||
@ -35,8 +35,8 @@ void* FixedMemoryPool__alloc(FixedMemoryPool* self) {
|
||||
void FixedMemoryPool__dealloc(FixedMemoryPool* self, void* p) {
|
||||
bool is_valid = (char*)p >= self->data && (char*)p < self->data_end;
|
||||
if(is_valid) {
|
||||
*self->_free_list_end = p;
|
||||
self->_free_list_end++;
|
||||
self->_free_list[self->_free_list_length] = p;
|
||||
self->_free_list_length++;
|
||||
} else {
|
||||
self->exceeded_bytes -= self->BlockSize;
|
||||
PK_FREE(p);
|
||||
|
||||
@ -97,18 +97,16 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
frame->ip++;
|
||||
|
||||
__NEXT_STEP:
|
||||
if(self->callbacks.tracefunc) {
|
||||
// TODO: implement tracing mechanism
|
||||
}
|
||||
|
||||
byte = codes[frame->ip];
|
||||
|
||||
#ifndef NDEBUG
|
||||
pk_print_stack(self, frame, byte);
|
||||
#endif
|
||||
|
||||
if(self->is_signal_interrupted) {
|
||||
self->is_signal_interrupted = false;
|
||||
py_exception(tp_KeyboardInterrupt, "");
|
||||
goto __ERROR;
|
||||
}
|
||||
|
||||
switch((Opcode)byte.op) {
|
||||
case OP_NO_OP: DISPATCH();
|
||||
/*****************************************/
|
||||
@ -199,13 +197,14 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
/*****************************************/
|
||||
case OP_LOAD_FAST: {
|
||||
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);
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
py_Ref val = &frame->locals[byte.arg];
|
||||
if(!py_isnil(val)) {
|
||||
PUSH(val);
|
||||
DISPATCH();
|
||||
}
|
||||
DISPATCH();
|
||||
py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
|
||||
UnboundLocalError(name);
|
||||
goto __ERROR;
|
||||
}
|
||||
case OP_LOAD_NAME: {
|
||||
assert(frame->is_locals_special);
|
||||
|
||||
@ -76,16 +76,8 @@ static bool generator__next__(int argc, py_Ref argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static void generator__gc_mark(void* ud){
|
||||
Generator* gen = ud;
|
||||
if(gen->frame) Frame__gc_mark(gen->frame);
|
||||
}
|
||||
|
||||
py_Type pk_generator__register() {
|
||||
py_Type type = pk_newtype("generator", tp_object, NULL, (py_Dtor)Generator__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, generator__gc_mark);
|
||||
|
||||
py_bindmagic(type, __iter__, pk_wrapper__self);
|
||||
py_bindmagic(type, __next__, generator__next__);
|
||||
return type;
|
||||
|
||||
@ -38,9 +38,12 @@ void ManagedHeap__collect_if_needed(ManagedHeap* self) {
|
||||
self->freed_ma[1] = self->freed_ma[2];
|
||||
self->freed_ma[2] = freed;
|
||||
int avg_freed = (self->freed_ma[0] + self->freed_ma[1] + self->freed_ma[2]) / 3;
|
||||
int upper = self->gc_threshold * 2;
|
||||
int lower = c11__max(PK_GC_MIN_THRESHOLD, self->gc_threshold / 2 + 1);
|
||||
self->gc_threshold = c11__min(c11__max(avg_freed, lower), upper);
|
||||
const int upper = PK_GC_MIN_THRESHOLD * 2;
|
||||
const int lower = PK_GC_MIN_THRESHOLD / 2;
|
||||
float free_ratio = (float)avg_freed / PK_GC_MIN_THRESHOLD;
|
||||
int new_threshold = self->gc_threshold * (1 / free_ratio);
|
||||
// printf("gc_threshold=%d, avg_freed=%d, new_threshold=%d\n", self->gc_threshold, avg_freed, new_threshold);
|
||||
self->gc_threshold = c11__min(c11__max(new_threshold, lower), upper);
|
||||
}
|
||||
|
||||
int ManagedHeap__collect(ManagedHeap* self) {
|
||||
|
||||
@ -60,18 +60,14 @@ py_TValue* TypeList__magic(py_TypeInfo* self, unsigned index) {
|
||||
return self->magic_1 + index;
|
||||
}
|
||||
|
||||
py_TValue* TypeList__magic_readonly_nullable(py_TypeInfo* self, unsigned index) {
|
||||
py_TValue* TypeList__magic_readonly(py_TypeInfo* self, unsigned index) {
|
||||
if(index > __xor__) {
|
||||
// common magic slots
|
||||
py_TValue* slot = TypeList__magic_common(self, index);
|
||||
if(py_isnil(slot)) return NULL;
|
||||
return slot;
|
||||
return TypeList__magic_common(self, index);
|
||||
}
|
||||
// uncommon magic slots
|
||||
if(self->magic_1 == NULL) return NULL;
|
||||
py_TValue* slot = self->magic_1 + index;
|
||||
if(py_isnil(slot)) return NULL;
|
||||
return slot;
|
||||
if(self->magic_1 == NULL) return py_NIL();
|
||||
return self->magic_1 + index;
|
||||
}
|
||||
|
||||
#undef CHUNK_SIZE
|
||||
|
||||
@ -68,10 +68,10 @@ void VM__ctor(VM* self) {
|
||||
self->callbacks.importfile = pk_default_importfile;
|
||||
self->callbacks.print = pk_default_print;
|
||||
self->callbacks.getchar = getchar;
|
||||
self->callbacks.tracefunc = NULL;
|
||||
|
||||
self->last_retval = *py_NIL();
|
||||
self->curr_exception = *py_NIL();
|
||||
self->is_signal_interrupted = false;
|
||||
self->is_curr_exc_handled = false;
|
||||
|
||||
self->ctx = NULL;
|
||||
@ -447,7 +447,9 @@ static bool
|
||||
}
|
||||
|
||||
FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall) {
|
||||
#ifndef NDEBUG
|
||||
pk_print_stack(self, self->top_frame, (Bytecode){0});
|
||||
#endif
|
||||
|
||||
py_Ref p1 = self->stack.sp - kwargc * 2;
|
||||
py_Ref p0 = p1 - argc - 2;
|
||||
@ -602,19 +604,6 @@ void PyObject__dtor(PyObject* self) {
|
||||
if(self->slots == -1) NameDict__dtor(PyObject__dict(self));
|
||||
}
|
||||
|
||||
void pk__mark_namedict(NameDict* dict) {
|
||||
for(int i = 0; i < dict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
|
||||
void pk__tp_set_marker(py_Type type, void (*gc_mark)(void*)) {
|
||||
py_TypeInfo* ti = pk__type_info(type);
|
||||
assert(ti->gc_mark == NULL);
|
||||
ti->gc_mark = gc_mark;
|
||||
}
|
||||
|
||||
void PyObject__mark(PyObject* obj) {
|
||||
assert(!obj->gc_marked);
|
||||
|
||||
@ -625,12 +614,51 @@ void PyObject__mark(PyObject* obj) {
|
||||
for(int i = 0; i < obj->slots; i++)
|
||||
pk__mark_value(p + i);
|
||||
} else if(obj->slots == -1) {
|
||||
NameDict* dict = PyObject__dict(obj);
|
||||
pk__mark_namedict(dict);
|
||||
NameDict* namedict = PyObject__dict(obj);
|
||||
for(int i = 0; i < namedict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
|
||||
py_TypeInfo* ti = pk__type_info(obj->type);
|
||||
if(ti->gc_mark) ti->gc_mark(PyObject__userdata(obj));
|
||||
void* ud = PyObject__userdata(obj);
|
||||
switch(obj->type) {
|
||||
case tp_list: {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->length; i++) {
|
||||
pk__mark_value(c11__at(py_TValue, self, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_dict: {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.length; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
pk__mark_value(&entry->key);
|
||||
pk__mark_value(&entry->val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_generator: {
|
||||
Generator* self = ud;
|
||||
if(self->frame) Frame__gc_mark(self->frame);
|
||||
break;
|
||||
}
|
||||
case tp_function: {
|
||||
function__gc_mark(ud);
|
||||
break;
|
||||
}
|
||||
case tp_code: {
|
||||
CodeObject* self = ud;
|
||||
CodeObject__gc_mark(self);
|
||||
break;
|
||||
}
|
||||
case tp_chunked_array2d: {
|
||||
c11_chunked_array2d__mark(ud);
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void FuncDecl__gc_mark(const FuncDecl* self) {
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include <limits.h>
|
||||
|
||||
static bool c11_array2d_like_is_valid(c11_array2d_like* self, unsigned int col, unsigned int row) {
|
||||
return col < self->n_cols && row < self->n_rows;
|
||||
static bool c11_array2d_like_is_valid(c11_array2d_like* self, int col, int row) {
|
||||
return col >= 0 && col < self->n_cols && row >= 0 && row < self->n_rows;
|
||||
}
|
||||
|
||||
static py_Ref c11_array2d__get(c11_array2d* self, int col, int row) {
|
||||
@ -1211,7 +1211,7 @@ void c11_chunked_array2d__dtor(c11_chunked_array2d* self) {
|
||||
c11_chunked_array2d_chunks__dtor(&self->chunks);
|
||||
}
|
||||
|
||||
static void c11_chunked_array2d__mark(void* ud) {
|
||||
void c11_chunked_array2d__mark(void* ud) {
|
||||
c11_chunked_array2d* self = ud;
|
||||
pk__mark_value(&self->default_T);
|
||||
pk__mark_value(&self->context_builder);
|
||||
@ -1291,7 +1291,6 @@ static bool chunked_array2d_view_chunks(int argc, py_Ref argv) {
|
||||
static void register_chunked_array2d(py_Ref mod) {
|
||||
py_Type type =
|
||||
py_newtype("chunked_array2d", tp_object, mod, (py_Dtor)c11_chunked_array2d__dtor);
|
||||
pk__tp_set_marker(type, c11_chunked_array2d__mark);
|
||||
assert(type == tp_chunked_array2d);
|
||||
|
||||
py_bind(py_tpobject(type),
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
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, (void (*)(void*))CodeObject__gc_mark);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
@ -90,8 +90,6 @@ void* py_getvmctx() { return pk_current_vm->ctx; }
|
||||
|
||||
void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
|
||||
|
||||
void py_interrupt() { pk_current_vm->is_signal_interrupted = true; }
|
||||
|
||||
void py_sys_setargv(int argc, char** argv) {
|
||||
py_GlobalRef sys = py_getmodule("sys");
|
||||
py_Ref argv_list = py_getdict(sys, py_name("argv"));
|
||||
@ -227,8 +225,9 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) {
|
||||
assert(py_ismagicname(name));
|
||||
py_TypeInfo* ti = pk__type_info(t);
|
||||
do {
|
||||
py_Ref f = TypeList__magic_readonly_nullable(ti, name);
|
||||
if(f != NULL) return f;
|
||||
py_Ref f = TypeList__magic_readonly(ti, name);
|
||||
assert(f != NULL);
|
||||
if(!py_isnil(f)) return f;
|
||||
ti = ti->base_ti;
|
||||
} while(ti);
|
||||
return NULL;
|
||||
|
||||
@ -773,10 +773,16 @@ py_TValue pk_builtins__register() {
|
||||
return *builtins;
|
||||
}
|
||||
|
||||
static void function__gc_mark(void* ud) {
|
||||
void function__gc_mark(void* ud) {
|
||||
Function* func = ud;
|
||||
if(func->globals) pk__mark_value(func->globals);
|
||||
if(func->closure) pk__mark_namedict(func->closure);
|
||||
if(func->closure) {
|
||||
NameDict* namedict = func->closure;
|
||||
for(int i = 0; i < namedict->length; i++) {
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, namedict, i);
|
||||
pk__mark_value(&kv->value);
|
||||
}
|
||||
}
|
||||
FuncDecl__gc_mark(func->decl);
|
||||
}
|
||||
|
||||
@ -794,9 +800,6 @@ static bool function__doc__(int argc, py_Ref argv) {
|
||||
py_Type pk_function__register() {
|
||||
py_Type type =
|
||||
pk_newtype("function", tp_object, NULL, (void (*)(void*))Function__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, function__gc_mark);
|
||||
|
||||
py_bindproperty(type, "__doc__", function__doc__, NULL);
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#define PK_DICT_MAX_COLLISION 4
|
||||
|
||||
static uint32_t Dict__next_cap(uint32_t cap) {
|
||||
switch(cap) {
|
||||
case 7: return 17;
|
||||
@ -53,22 +51,7 @@ static uint32_t Dict__next_cap(uint32_t cap) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint64_t hash;
|
||||
py_TValue key;
|
||||
py_TValue val;
|
||||
} DictEntry;
|
||||
|
||||
typedef struct {
|
||||
int _[PK_DICT_MAX_COLLISION];
|
||||
} DictIndex;
|
||||
|
||||
typedef struct {
|
||||
int length;
|
||||
uint32_t capacity;
|
||||
DictIndex* indices;
|
||||
c11_vector /*T=DictEntry*/ entries;
|
||||
} Dict;
|
||||
|
||||
typedef struct {
|
||||
DictEntry* curr;
|
||||
@ -525,21 +508,9 @@ static bool dict_values(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dict__gc_mark(void* ud) {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.length; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
pk__mark_value(&entry->key);
|
||||
pk__mark_value(&entry->val);
|
||||
}
|
||||
}
|
||||
|
||||
py_Type pk_dict__register() {
|
||||
py_Type type = pk_newtype("dict", tp_object, NULL, (void (*)(void*))Dict__dtor, false, false);
|
||||
|
||||
pk__tp_set_marker(type, dict__gc_mark);
|
||||
|
||||
py_bindmagic(type, __new__, dict__new__);
|
||||
py_bindmagic(type, __init__, dict__init__);
|
||||
py_bindmagic(type, __getitem__, dict__getitem__);
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
typedef c11_vector List;
|
||||
|
||||
void py_newlist(py_Ref out) {
|
||||
List* ud = py_newobject(out, tp_list, 0, sizeof(List));
|
||||
c11_vector__ctor(ud, sizeof(py_TValue));
|
||||
@ -404,19 +402,10 @@ static bool list__contains__(int argc, py_Ref argv) {
|
||||
return pk_arraycontains(py_arg(0), py_arg(1));
|
||||
}
|
||||
|
||||
static void list__gc_mark(void* ud) {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->length; i++) {
|
||||
pk__mark_value(c11__at(py_TValue, self, i));
|
||||
}
|
||||
}
|
||||
|
||||
py_Type pk_list__register() {
|
||||
py_Type type =
|
||||
pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true);
|
||||
|
||||
pk__tp_set_marker(type, list__gc_mark);
|
||||
|
||||
py_bindmagic(type, __len__, list__len__);
|
||||
py_bindmagic(type, __eq__, list__eq__);
|
||||
py_bindmagic(type, __ne__, list__ne__);
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
|
||||
#include "pocketpy.h"
|
||||
|
||||
#define py_interrupt()
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user