From facd1c0ce68540df13b16b63d23679b697a6af8f Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 4 Jul 2024 19:55:24 +0800 Subject: [PATCH] some fix --- include/pocketpy/interpreter/vm.h | 6 +- include/pocketpy/pocketpy.h | 2 +- src/interpreter/ceval.c | 6 +- src/interpreter/py_number.c | 2 +- src/interpreter/vm.c | 100 ++++++++++++++-------------- src/public/vm.c | 13 ++-- tests/00_tmp.py | 104 ++++++++++++++++++++++++++++++ tests/01_int.py | 8 +-- 8 files changed, 181 insertions(+), 60 deletions(-) create mode 100644 tests/00_tmp.py diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 99d03a7c..1c36490a 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -1,5 +1,6 @@ #pragma once +#include "pocketpy/objects/codeobject.h" #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/gc.h" #include "pocketpy/interpreter/frame.h" @@ -70,8 +71,6 @@ void pk_VM__dtor(pk_VM* self); void pk_VM__push_frame(pk_VM* self, Frame* frame); void pk_VM__pop_frame(pk_VM* self); -void pk_VM__init_builtins(pk_VM* self); - typedef enum pk_FrameResult { RES_RETURN, RES_CALL, @@ -89,7 +88,10 @@ py_Type pk_VM__new_type(pk_VM* self, pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall); +const char* pk_opname(Opcode op); + // type registration +void pk_number__register(); py_Type pk_str__register(); py_Type pk_bytes__register(); py_Type pk_list__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index ec6f1444..d84d34d3 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -117,7 +117,7 @@ bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ #define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4)) -#define TypeError(x) false +#define TypeError(...) false #define py_arg(i) py_offset(argv, i) #define py_checkargc(n) \ if(argc != n) return TypeError() diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 65a047cd..41635cc7 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -89,6 +89,9 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { __NEXT_STEP: byte = *frame->ip; + // log + printf("byte.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame)); + switch((Opcode)byte.op) { case OP_NO_OP: DISPATCH(); /*****************************************/ @@ -614,6 +617,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { case OP_CALL: { pk_ManagedHeap__collect_if_needed(&self->heap); vectorcall_opcall(byte.arg & 0xFF, byte.arg >> 8); + DISPATCH(); } case OP_CALL_VARGS: { assert(false); @@ -667,7 +671,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { __ERROR: // 1. Exception can be handled inside the current frame // 2. Exception need to be propagated to the upper frame - printf("byte.op: %d, line: %d\n", byte.op, Frame__lineno(frame)); + printf("error.op: %s, line: %d\n", pk_opname(byte.op), Frame__lineno(frame)); assert(false); return RES_ERROR; } diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index 1a92df13..5c0e6526 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -342,7 +342,7 @@ static bool _py_float__new__(int argc, py_Ref argv) { return true; } -void pk_VM__init_builtins(pk_VM* self) { +void pk_number__register() { /****** tp_int & tp_float ******/ py_bindmagic(tp_int, __add__, _py_int__add__); py_bindmagic(tp_float, __add__, _py_float__add__); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index e8469f52..d145f6ca 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -41,6 +41,7 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self, // create type object with __dict__ pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type)); + *(py_Type*)PyObject__userdata(typeobj) = index; self->self = (py_TValue){ .type = typeobj->type, .is_ptr = true, @@ -55,6 +56,13 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self, void pk_TypeInfo__dtor(pk_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); } +static bool _py_object__new__(int argc, py_Ref argv) { + assert(argc >= 1); + py_Type cls = argv[0].type; + py_newobject(py_retval(), cls, 0, 0); + return true; +} + void pk_VM__ctor(pk_VM* self) { self->top_frame = NULL; @@ -158,7 +166,10 @@ void pk_VM__ctor(pk_VM* self) { py_setdict(&self->builtins, py_name("NotImplemented"), &tmp); /* Do Buildin Bindings*/ - pk_VM__init_builtins(self); + pk_number__register(); + // object.__new__ + py_bindmagic(tp_object, __new__, _py_object__new__); + self->main = *py_newmodule("__main__", NULL); } @@ -208,7 +219,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo // handle boundmethod, do a patch if(p0->type == tp_bound_method) { assert(false); - assert(py_isnull(p0+1)); // self must be NULL + assert(py_isnull(p0 + 1)); // self must be NULL // BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable); // callable = bm.func; // get unbound method // callable_t = _tp(callable); @@ -218,7 +229,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo } // PyVar* _base = args.begin(); - py_Ref argv = py_isnull(p0+1) ? p0+2 : p0+1; + py_Ref argv = py_isnull(p0 + 1) ? p0 + 2 : p0 + 1; #if 0 if(callable_t == tp_function) { @@ -301,7 +312,8 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo // if(f.argc != -1) { // if(KWARGC != 0) // TypeError( - // "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1"); + // "old-style native_func does not accept keyword arguments. If you want to + // skip this check, specify `argc` to -1"); // if(args.size() != f.argc) { // vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); // } @@ -314,58 +326,52 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t ARGC, uint16_t KWARGC, bo return RES_RETURN; } -#if 0 if(p0->type == tp_type) { - // [type, NULL, args..., kwargs...] - PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__); - PyVar obj; - assert(new_f && (!p0[1])); - if(PyVar__IS_OP(&new_f, &__cached_object_new)) { - // fast path for object.__new__ - obj = vm->new_object(PK_OBJ_GET(Type, callable)); - } else { - PUSH(new_f); - PUSH(PY_NULL); - PUSH(callable); // cls - for(PyVar o: args) - PUSH(o); - for(PyVar o: kwargs) - PUSH(o); - // if obj is not an instance of `cls`, the behavior is undefined - obj = vectorcall(ARGC + 1, KWARGC); - } + // [cls, NULL, args..., kwargs...] + py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__); + assert(new_f && py_isnull(p0 + 1)); - // __init__ - PyVar self; - callable = get_unbound_method(obj, __init__, &self, false); - if(callable) { - callable_t = _tp(callable); - // replace `NULL` with `self` - p1[-(ARGC + 2)] = callable; - p1[-(ARGC + 1)] = self; - // [init_f, self, args..., kwargs...] - vectorcall(ARGC, KWARGC); - // We just discard the return value of `__init__` - // in cpython it raises a TypeError if the return value is not None + // prepare a copy of args and kwargs + int span = self->stack.sp - argv; + *self->stack.sp++ = *new_f; // push __new__ + *self->stack.sp++ = *p0; // push cls + memcpy(self->stack.sp, argv, span * sizeof(py_TValue)); + self->stack.sp += span; + + // [new_f, cls, args..., kwargs...] + pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false); + if(res == RES_ERROR) return RES_ERROR; + assert(res == RES_RETURN); + // by recursively using vectorcall, args and kwargs are consumed + // [cls, NULL, args..., kwargs...] + + // try __init__ + // NOTE: previous we use `get_unbound_method` but here we just use `tpfindmagic` + py_Ref init_f = py_tpfindmagic(py_totype(p0), __init__); + if(init_f) { + // do an inplace patch + *p0 = *init_f; // __init__ + p0[1] = self->last_retval; // self + // [__init__, self, args..., kwargs...] + pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false); + if(res == RES_ERROR) return RES_ERROR; + assert(res == RES_RETURN); } else { // manually reset the stack - s_data.reset(p0); + self->stack.sp = p0; } - return obj; + return RES_RETURN; } // handle `__call__` overload - PyVar self; - PyVar call_f = get_unbound_method(callable, __call__, &self, false); - if(self) { - p1[-(ARGC + 2)] = call_f; - p1[-(ARGC + 1)] = self; - // [call_f, self, args..., kwargs...] - return vectorcall(ARGC, KWARGC, op_call); + if(py_getunboundmethod(p0, __call__, false, p0, p0 + 1)) { + // [__call__, self, args..., kwargs...] + pk_FrameResult res = pk_VM__vectorcall(self, ARGC, KWARGC, false); + if(res == RES_ERROR) return RES_ERROR; + assert(res == RES_RETURN); } - TypeError(_type_name(vm, callable_t).escape() + " object is not callable"); -#endif - + + TypeError("'%t' object is not callable", p0->type); PK_UNREACHABLE(); } diff --git a/src/public/vm.c b/src/public/vm.c index 8e5fcc80..f72e091c 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -1,3 +1,4 @@ +#include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/sourcedata.h" #include "pocketpy/pocketpy.h" @@ -25,13 +26,16 @@ void py_finalize() { pk_MemoryPools__finalize(); } -static void disassemble(CodeObject* co) { +const char* pk_opname(Opcode op){ const static char* OP_NAMES[] = { #define OPCODE(name) #name, #include "pocketpy/xmacros/opcodes.h" #undef OPCODE }; + return OP_NAMES[op]; +} +static void disassemble(CodeObject* co) { c11_vector /*T=int*/ jumpTargets; c11_vector__ctor(&jumpTargets, sizeof(int)); for(int i = 0; i < co->codes.count; i++) { @@ -71,9 +75,9 @@ static void disassemble(CodeObject* co) { snprintf(buf, sizeof(buf), "%-8s%-3s%-3d ", line, pointer, i); c11_sbuf__write_cstr(&ss, buf); - c11_sbuf__write_cstr(&ss, OP_NAMES[byte.op]); + c11_sbuf__write_cstr(&ss, pk_opname(byte.op)); c11_sbuf__write_char(&ss, ex.is_virtual ? '*' : ' '); - int padding = 24 - strlen(OP_NAMES[byte.op]); + int padding = 24 - strlen(pk_opname(byte.op)); for(int j = 0; j < padding; j++) c11_sbuf__write_char(&ss, ' '); @@ -196,7 +200,7 @@ bool py_getunboundmethod(const py_Ref self, bool fallback, py_Ref out, py_Ref out_self) { - return -1; + return false; } pk_TypeInfo* pk_tpinfo(const py_Ref self) { @@ -205,6 +209,7 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self) { } py_Ref py_tpfindmagic(py_Type t, py_Name name) { + assert(t); assert(py_ismagicname(name)); pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data; do { diff --git a/tests/00_tmp.py b/tests/00_tmp.py new file mode 100644 index 00000000..732db0db --- /dev/null +++ b/tests/00_tmp.py @@ -0,0 +1,104 @@ +# test int literals +assert 0xffff == 65535 +assert 0xAAFFFF == 11206655 +assert 0x7fffffff == 2147483647 +assert -0xffff == -65535 +assert -0xAAFFFF == -11206655 +assert -0x7fffffff == -2147483647 +# test 64-bit +assert 2**60-1 + 546 - 0xfffffffffffff == 1148417904979477026 + +# test oct literals +assert 0o1234 == 668 +assert 0o17777777777 == 2147483647 +assert -0o1234 == -668 +assert -0o17777777777 == -2147483647 + +# test binary literals +assert 0b10010 == 18 +assert -0b10010 == -18 +assert 0b11111111111111111111111111111111 == 4294967295 +assert -0b11111 == -31 + +# test == != >= <= < > +assert -1 == -1 +assert -1 != 1 +assert -1 >= -1 +assert -1 <= -1 +assert -1 < 1 +assert -1 > -2 + +# test + - * % ** // +assert -1 + 1 == 0 +assert -1 - 1 == -2 +assert 4 * -1 == -4 +assert 5 % 2 == 1 +assert 2 ** 3 == 8 +assert 4 // 2 == 2 +assert 5 // 2 == 2 + +# test += -= *= //= +x = 3 +x += 1 +assert x == 4 +x -= 1 +assert x == 3 +x *= 2 +assert x == 6 +x //= 2 +assert x == 3 + +# test bit_length +assert (1).bit_length() == 1 +assert (2).bit_length() == 2 +assert (3).bit_length() == 2 + +assert (-1).bit_length() == 1 +assert (-2).bit_length() == 2 +assert (-3).bit_length() == 2 + +assert (123123123123123).bit_length() == 47 +assert (-3123123123).bit_length() == 32 + +# test int() +assert int() == 0 +assert int(True) == 1 +assert int(False) == 0 + +assert int(1) == 1 +assert int(1.0) == 1 +assert int(1.1) == 1 +assert int(1.9) == 1 +assert int(-1.9) == -1 +assert int(1.5) == 1 +assert int(-1.5) == -1 +assert int("123") == 123 + +assert int("0x123", 16) == 291 +assert int("0o123", 8) == 83 +assert int("-0x123", 16) == -291 +assert int("-0o123", 8) == -83 +assert int("-123") == -123 +assert int("+123") == 123 + +# test >> << & | ^ +assert 12 >> 1 == 6 +assert 12 << 1 == 24 +assert 12 & 1 == 0 +assert 12 | 1 == 13 +assert 12 ^ 1 == 13 + +# test high precision int pow +assert 7**21 == 558545864083284007 +assert 2**60 == 1152921504606846976 +assert -2**60 == -1152921504606846976 +assert 4**13 == 67108864 +assert (-4)**13 == -67108864 + +assert ~3 == -4 +assert ~-3 == 2 +assert ~0 == -1 + +# test __str__, __repr__ +assert str(1) == '1' +assert repr(1) == '1' \ No newline at end of file diff --git a/tests/01_int.py b/tests/01_int.py index 2c13964c..733a5cb0 100644 --- a/tests/01_int.py +++ b/tests/01_int.py @@ -48,10 +48,6 @@ assert x == 6 x //= 2 assert x == 3 -# test __str__, __repr__ -assert str(1) == '1' -assert repr(1) == '1' - # test bit_length assert (1).bit_length() == 1 assert (2).bit_length() == 2 @@ -103,6 +99,10 @@ assert ~3 == -4 assert ~-3 == 2 assert ~0 == -1 +# test __str__, __repr__ +assert str(1) == '1' +assert repr(1) == '1' + try: 1 // 0 exit(1)