blueloveTH 1 год назад
Родитель
Сommit
cde78ea481

+ 2 - 2
include/pocketpy/interpreter/vm.h

@@ -63,8 +63,8 @@ typedef struct pk_VM {
     py_TValue last_retval;
     py_TValue reg[8];   // users' registers
 
-    PyObject* __curr_class;
-    PyObject* __cached_object_new;
+    py_TValue __curr_class;
+    py_TValue __cached_object_new;
     FuncDecl_ __dynamic_func_decl;
     py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
 

+ 2 - 1
include/pocketpy/objects/base.h

@@ -29,7 +29,8 @@ typedef struct py_TValue{
     };
 } py_TValue;
 
-static_assert(sizeof(py_TValue) <= 16, "!sizeof(py_TValue) <= 16");
+// 16 bytes to make py_arg() macro work
+static_assert(sizeof(py_TValue) == 16, "sizeof(py_TValue) != 16");
 
 /* predefined vars */
 static const py_Type tp_object = {1}, tp_type = {2};

+ 14 - 4
include/pocketpy/pocketpy.h

@@ -40,12 +40,12 @@ void py_newbool(py_Ref, bool);
 void py_newstr(py_Ref, const char*);
 void py_newstrn(py_Ref, const char*, int);
 // void py_newfstr(py_Ref, const char*, ...);
-// void py_newbytes(py_Ref, const uint8_t*, int);
+void py_newbytes(py_Ref, const unsigned char*, int);
 void py_newnone(py_Ref);
 void py_newnull(py_Ref);
 
-void py_newtuple(py_Ref, int);
-// void py_newlist(py_Ref);
+void py_newtuple(py_Ref, int count);
+void py_newlist(py_Ref);
 
 // new style decl-based function
 void py_newfunction(py_Ref out, py_CFunction, const char* sig);
@@ -101,6 +101,8 @@ bool py_istype(const py_Ref, py_Type);
 // bool py_issubclass(py_Type derived, py_Type base);
 
 /************* References *************/
+#define py_arg(i)   (py_Ref)((char*)argv+((i)<<4))
+
 py_Ref py_getreg(int i);
 void py_setreg(int i, const py_Ref val);
 
@@ -114,9 +116,13 @@ py_Ref py_getupvalue(py_Ref self);
 void py_setupvalue(py_Ref self, const py_Ref val);
 
 /// Gets the attribute of the object.
-int py_getattr(const py_Ref self, py_Name name, py_Ref out);
+bool py_getattr(const py_Ref self, py_Name name, py_Ref out);
+/// Gets the unbound method of the object.
+bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self);
 /// Sets the attribute of the object.
 int py_setattr(py_Ref self, py_Name name, const py_Ref val);
+/// Deletes the attribute of the object.
+int py_delattr(py_Ref self, py_Name name);
 
 /// Equivalent to `*dst = *src`.
 void py_assign(py_Ref dst, const py_Ref src);
@@ -193,6 +199,10 @@ void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val);
 void py_dict__delitem(py_Ref self, const py_Ref key);
 void py_dict__clear(py_Ref self);
 
+// internal functions
+typedef struct pk_TypeInfo pk_TypeInfo;
+pk_TypeInfo* pk_tpinfo(const py_Ref self);
+
 #ifdef __cplusplus
 }
 #endif

+ 0 - 2
include/pocketpy/xmacros/opcodes.h

@@ -29,14 +29,12 @@ OPCODE(LOAD_ATTR)
 OPCODE(LOAD_CLASS_GLOBAL)
 OPCODE(LOAD_METHOD)
 OPCODE(LOAD_SUBSCR)
-OPCODE(LOAD_SUBSCR_FAST)
 
 OPCODE(STORE_FAST)
 OPCODE(STORE_NAME)
 OPCODE(STORE_GLOBAL)
 OPCODE(STORE_ATTR)
 OPCODE(STORE_SUBSCR)
-OPCODE(STORE_SUBSCR_FAST)
 
 OPCODE(DELETE_FAST)
 OPCODE(DELETE_NAME)

+ 2 - 14
src/compiler/compiler.c

@@ -1001,26 +1001,14 @@ void SubscrExpr__emit_(Expr* self_, Ctx* ctx) {
     SubscrExpr* self = (SubscrExpr*)self_;
     vtemit_(self->lhs, ctx);
     vtemit_(self->rhs, ctx);
-    Bytecode last_bc = c11_vector__back(Bytecode, &ctx->co->codes);
-    if(self->rhs->vt->is_name && last_bc.op == OP_LOAD_FAST) {
-        Ctx__revert_last_emit_(ctx);
-        Ctx__emit_(ctx, OP_LOAD_SUBSCR_FAST, last_bc.arg, self->line);
-    } else {
-        Ctx__emit_(ctx, OP_LOAD_SUBSCR, BC_NOARG, self->line);
-    }
+    Ctx__emit_(ctx, OP_LOAD_SUBSCR, BC_NOARG, self->line);
 }
 
 bool SubscrExpr__emit_store(Expr* self_, Ctx* ctx) {
     SubscrExpr* self = (SubscrExpr*)self_;
     vtemit_(self->lhs, ctx);
     vtemit_(self->rhs, ctx);
-    Bytecode last_bc = c11_vector__back(Bytecode, &ctx->co->codes);
-    if(self->rhs->vt->is_name && last_bc.op == OP_LOAD_FAST) {
-        Ctx__revert_last_emit_(ctx);
-        Ctx__emit_(ctx, OP_STORE_SUBSCR_FAST, last_bc.arg, self->line);
-    } else {
-        Ctx__emit_(ctx, OP_STORE_SUBSCR, BC_NOARG, self->line);
-    }
+    Ctx__emit_(ctx, OP_STORE_SUBSCR, BC_NOARG, self->line);
     return true;
 }
 

+ 279 - 39
src/interpreter/ceval.c

@@ -8,6 +8,8 @@ int UnboundLocalError(py_Name name) { return -1; }
 
 int NameError(py_Name name) { return -1; }
 
+#define AttributeError(obj, name)
+
 #define DISPATCH()                                                                                 \
     do {                                                                                           \
         frame->ip++;                                                                               \
@@ -26,15 +28,39 @@ int NameError(py_Name name) { return -1; }
 
 /* Stack manipulation macros */
 // https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
-#define TOP() self->stack.sp[-1]
-#define SECOND() self->stack.sp[-2]
-#define THIRD() self->stack.sp[-3]
+#define TOP() (self->stack.sp - 1)
+#define SECOND() (self->stack.sp - 2)
+#define THIRD() (self->stack.sp - 3)
+#define FOURTH() (self->stack.sp - 4)
 #define STACK_SHRINK(n) (self->stack.sp -= n)
-#define PUSH(v) (*self->stack.sp++ = v)
+#define PUSH(v) (*self->stack.sp++ = *v)
 #define POP() (--self->stack.sp)
 #define POPX() (*--self->stack.sp)
 #define SP() (self->stack.sp)
 
+static void pack_stack_values(int n) {
+    assert(n > 1);
+    pk_VM* self = pk_current_vm;
+    py_TValue tmp;
+    py_newtuple(&tmp, n);
+    for(int i = 0; i < n; i++)
+        py_tuple__setitem(&tmp, i, SP() - n + i);
+    STACK_SHRINK(n);
+    PUSH(&tmp);
+}
+
+// n == 1 is the most likely result
+#define HANDLE_RETVAL(n)                                                                           \
+    if(n != 1) {                                                                                   \
+        if(n == 0) {                                                                               \
+            PUSH(&self->None);                                                                     \
+        } else if(n > 1) {                                                                         \
+            pack_stack_values(n);                                                                  \
+        } else {                                                                                   \
+            goto __ERROR;                                                                          \
+        }                                                                                          \
+    }
+
 pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
     Frame* frame = self->top_frame;
     const Frame* base_frame = frame;
@@ -72,39 +98,37 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                 PUSH(SECOND());  // [a, b, a, b]
                 DISPATCH();
             case OP_ROT_TWO: {
-                py_TValue tmp = TOP();
-                TOP() = SECOND();
-                SECOND() = tmp;
+                py_TValue tmp = *TOP();
+                *TOP() = *SECOND();
+                *SECOND() = tmp;
                 DISPATCH();
             }
             case OP_ROT_THREE: {
                 // [a, b, c] -> [c, a, b]
-                py_TValue _0 = TOP();
-                TOP() = SECOND();
-                SECOND() = THIRD();
-                THIRD() = _0;
+                py_TValue tmp = *TOP();
+                *TOP() = *SECOND();
+                *SECOND() = *THIRD();
+                *THIRD() = tmp;
                 DISPATCH();
             }
             case OP_PRINT_EXPR:
-                if(TOP().type != tp_none_type) {
-                    int err = py_repr(&TOP());
+                if(TOP()->type != tp_none_type) {
+                    int err = py_repr(TOP());
                     if(err) goto __ERROR;
-                    self->_stdout("%s\n", py_tostr(&TOP()));
+                    self->_stdout("%s\n", py_tostr(TOP()));
                     POP();
                 }
                 POP();
                 DISPATCH();
             /*****************************************/
-            case OP_LOAD_CONST:
-                PUSH(c11__getitem(py_TValue, &frame->co->consts, byte.arg));
-                DISPATCH();
-            case OP_LOAD_NONE: PUSH(self->None); DISPATCH();
-            case OP_LOAD_TRUE: PUSH(self->True); DISPATCH();
-            case OP_LOAD_FALSE: PUSH(self->False); DISPATCH();
+            case OP_LOAD_CONST: PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg)); DISPATCH();
+            case OP_LOAD_NONE: PUSH(&self->None); DISPATCH();
+            case OP_LOAD_TRUE: PUSH(&self->True); DISPATCH();
+            case OP_LOAD_FALSE: PUSH(&self->False); DISPATCH();
             /*****************************************/
             case OP_LOAD_SMALL_INT: py_newint(SP()++, (int64_t)(int16_t)byte.arg); DISPATCH();
             /*****************************************/
-            case OP_LOAD_ELLIPSIS: PUSH(self->Ellipsis); DISPATCH();
+            case OP_LOAD_ELLIPSIS: PUSH(&self->Ellipsis); DISPATCH();
             case OP_LOAD_FUNCTION: {
                 // FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
                 // py_TValue obj;
@@ -126,8 +150,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                 DISPATCH();
                 /*****************************************/
             case OP_LOAD_FAST: {
-                PUSH(frame->locals[byte.arg]);
-                if(py_isnull(&TOP())) {
+                PUSH(&frame->locals[byte.arg]);
+                if(py_isnull(TOP())) {
                     py_Name name = c11__getitem(uint16_t, &frame->co->varnames, byte.arg);
                     UnboundLocalError(name);
                     goto __ERROR;
@@ -142,22 +166,22 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                         UnboundLocalError(name);
                         goto __ERROR;
                     }
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = Frame__f_closure_try_get(frame, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = Frame__f_globals_try_get(frame, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = py_getdict(&self->builtins, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 NameError(name);
@@ -167,17 +191,17 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                 py_Name name = byte.arg;
                 py_Ref tmp = Frame__f_closure_try_get(frame, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = Frame__f_globals_try_get(frame, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = py_getdict(&self->builtins, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 NameError(name);
@@ -187,27 +211,203 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                 py_Name name = byte.arg;
                 py_Ref tmp = Frame__f_globals_try_get(frame, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 tmp = py_getdict(&self->builtins, name);
                 if(tmp != NULL) {
-                    PUSH(*tmp);
+                    PUSH(tmp);
                     DISPATCH();
                 }
                 NameError(name);
                 goto __ERROR;
             }
             case OP_LOAD_ATTR: {
-                int err = py_getattr(&TOP(), byte.arg, &TOP());
+                if(!py_getattr(TOP(), byte.arg, TOP())) {
+                    AttributeError(TOP(), byte.arg);
+                    goto __ERROR;
+                }
+                DISPATCH();
+            }
+            case OP_LOAD_CLASS_GLOBAL: {
+                assert(self->__curr_class.type);
+                py_Name name = byte.arg;
+                if(py_getattr(&self->__curr_class, name, SP())) {
+                    SP()++;
+                    DISPATCH();
+                }
+                // load global if attribute not found
+                py_Ref tmp = Frame__f_globals_try_get(frame, name);
+                if(tmp) {
+                    PUSH(tmp);
+                    DISPATCH();
+                }
+                tmp = py_getdict(&self->builtins, name);
+                if(tmp) {
+                    PUSH(tmp);
+                    DISPATCH();
+                }
+                NameError(name);
+                goto __ERROR;
+            }
+            case OP_LOAD_METHOD: {
+                // `py_getunboundmethod` never fails on `fallback=true`
+                py_getunboundmethod(TOP(), byte.arg, true, TOP(), SP());
+                SP()++;
+                DISPATCH();
+            }
+            case OP_LOAD_SUBSCR: {
+                // [a, b] -> a[b]
+                int n = py_callmethod(SECOND(), __getitem__, TOP());
+                HANDLE_RETVAL(n);
+                // [a, b, retval]
+                *THIRD() = *TOP();  // [retval, b, retval]
+                STACK_SHRINK(2);    // [retval]
+                DISPATCH();
+            }
+            case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
+            case OP_STORE_NAME: {
+                py_Name _name = byte.arg;
+                py_TValue _0 = POPX();
+                if(frame->function) {
+                    py_Ref slot = Frame__f_locals_try_get(frame, _name);
+                    if(slot != NULL) {
+                        *slot = _0;  // store in locals if possible
+                    } else {
+                        // Function& func = frame->_callable->as<Function>();
+                        // if(func.decl == __dynamic_func_decl) {
+                        //     assert(func._closure != nullptr);
+                        //     func._closure->set(_name, _0);
+                        // } else {
+                        //     NameError(_name);
+                        //     goto __ERROR;
+                        // }
+                    }
+                } else {
+                    pk_NameDict__set(Frame__f_globals(frame), _name, _0);
+                }
+                DISPATCH();
+            }
+            case OP_STORE_GLOBAL:
+                pk_NameDict__set(Frame__f_globals(frame), byte.arg, POPX());
+                DISPATCH();
+
+            case OP_STORE_ATTR: {
+                int err = py_setattr(TOP(), byte.arg, SECOND());
+                if(err) goto __ERROR;
+                STACK_SHRINK(2);
+                DISPATCH();
+            }
+            case OP_STORE_SUBSCR: {
+                // [val, a, b] -> a[b] = val
+                py_TValue* backup = SP();
+                PUSH(THIRD());  // [val, a, b, val]
+                bool ok = py_getunboundmethod(THIRD(), __setitem__, false, FOURTH(), THIRD());
+                if(!ok) {
+                    // __setitem__ not found
+                    goto __ERROR;
+                }
+                // [__setitem__, self, b, val]
+                int n = py_vectorcall(3, 0);
+                if(n < 0) goto __ERROR;
+                SP() = backup;  // discard retval if any
+                DISPATCH();
+            }
+            case OP_DELETE_FAST: {
+                py_Ref tmp = &frame->locals[byte.arg];
+                if(py_isnull(tmp)) {
+                    UnboundLocalError(c11__getitem(uint16_t, &frame->co->varnames, byte.arg));
+                    goto __ERROR;
+                }
+                py_newnull(tmp);
+                DISPATCH();
+            }
+            case OP_DELETE_NAME: {
+                StrName name = byte.arg;
+                if(frame->function) {
+                    py_TValue* slot = Frame__f_locals_try_get(frame, name);
+                    if(slot) {
+                        py_newnull(slot);
+                    } else {
+                        // Function& func = frame->_callable->as<Function>();
+                        // if(func.decl == __dynamic_func_decl) {
+                        //     assert(func._closure != nullptr);
+                        //     bool ok = func._closure->del(_name);
+                        //     if(!ok) vm->NameError(_name);
+                        // } else {
+                        //     vm->NameError(_name);
+                        // }
+                    }
+                } else {
+                    // if(!frame->f_globals().del(_name)) vm->NameError(_name);
+                    bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
+                    if(!ok) {
+                        NameError(name);
+                        goto __ERROR;
+                    }
+                }
+                DISPATCH();
+            }
+            case OP_DELETE_GLOBAL: {
+                StrName name = byte.arg;
+                bool ok = pk_NameDict__del(Frame__f_globals(frame), name);
+                if(!ok) {
+                    NameError(name);
+                    goto __ERROR;
+                }
+                DISPATCH();
+            }
+
+            case OP_DELETE_ATTR: {
+                int err = py_delattr(TOP(), byte.arg);
                 if(err) goto __ERROR;
+                POP();
+                DISPATCH();
+            }
+
+            case OP_DELETE_SUBSCR: {
+                // [a, b] -> del a[b]
+                py_Ref backup = SP();
+                int n = py_callmethod(SECOND(), __delitem__, TOP());
+                if(n < 0) { goto __ERROR; }
+                SP() = backup;  // discard retval if any
                 DISPATCH();
             }
-                /*******************/
 
-                // ...
+                /*****************************************/
+
+            case OP_BUILD_LONG: {
+                py_Ref _0 = py_getdict(&self->builtins, pk_id_long);
+                assert(_0 != NULL);
+                int n = py_call(_0, TOP());
+                if(n < 0) goto __ERROR;
+                assert(n == 1);
+                // [x, long(x)]
+                *SECOND() = *TOP();  // [long(x), long(x)]
+                POP();               // [long(x)]
+                DISPATCH();
+            }
 
-                /*******************/
+            case OP_BUILD_IMAG: {
+                py_Ref _0 = py_getdict(&self->builtins, pk_id_complex);
+                assert(_0 != NULL);
+                py_TValue zero;
+                py_newint(&zero, 0);
+                int n = py_call(_0, &zero, TOP());
+                if(n < 0) goto __ERROR;
+                assert(n == 1);
+                // [x, complex(0, x)]
+                *SECOND() = *TOP();  // [complex(0, x), complex(0, x)]
+                POP();               // [complex(0, x)]
+                DISPATCH();
+            }
+            case OP_BUILD_BYTES: {
+                py_Str* s = py_touserdata(TOP());
+                unsigned char* p = (unsigned char*)malloc(s->size);
+                memcpy(p, py_Str__data(s), s->size);
+                py_newbytes(SP()++, p, s->size);
+                DISPATCH();
+            }
             case OP_BUILD_TUPLE: {
                 py_TValue tmp;
                 py_newtuple(&tmp, byte.arg);
@@ -216,19 +416,59 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
                     py_tuple__setitem(&tmp, i, begin + i);
                 }
                 SP() = begin;
-                PUSH(tmp);
+                PUSH(&tmp);
                 DISPATCH();
             }
+            // case OP_BUILD_LIST: {
+            //     PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
+            //     STACK_SHRINK(byte.arg);
+            //     PUSH(_0);
+            //     DISPATCH();
+            // }
+            // case OP_BUILD_DICT: {
+            //     if(byte.arg == 0) {
+            //         PUSH(VAR(Dict()));
+            //         DISPATCH()
+            //     }
+            //     PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
+            //     _0 = call(_t(tp_dict), _0);
+            //     STACK_SHRINK(byte.arg);
+            //     PUSH(_0);
+            //     DISPATCH();
+            // }
+            // case OP_BUILD_SET: {
+            //     PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
+            //     _0 = call(builtins->attr()[pk_id_set], _0);
+            //     STACK_SHRINK(byte.arg);
+            //     PUSH(_0);
+            //     DISPATCH();
+            // }
+            // case OP_BUILD_SLICE: {
+            //     PyVar _2 = POPX();  // step
+            //     PyVar _1 = POPX();  // stop
+            //     PyVar _0 = POPX();  // start
+            //     PUSH(VAR(Slice(_0, _1, _2)));
+            //     DISPATCH();
+            // }
+            // case OP_BUILD_STRING: {
+            //     SStream ss;
+            //     ArgsView view = STACK_VIEW(byte.arg);
+            //     for(PyVar obj: view)
+            //         ss << py_str(obj);
+            //     STACK_SHRINK(byte.arg);
+            //     PUSH(VAR(ss.str()));
+            //     DISPATCH();
+            // }
             /**************************** */
             case OP_RETURN_VALUE: {
-                py_TValue tmp =  byte.arg == BC_NOARG ? POPX() : self->None;
+                py_TValue tmp = byte.arg == BC_NOARG ? POPX() : self->None;
                 pk_VM__pop_frame(self);
                 if(frame == base_frame) {  // [ frameBase<- ]
                     self->last_retval = tmp;
                     return RES_RETURN;
                 } else {
                     frame = self->top_frame;
-                    PUSH(tmp);
+                    PUSH(&tmp);
                     goto __NEXT_FRAME;
                 }
                 DISPATCH();

+ 1 - 1
src/interpreter/py_number.c

@@ -175,7 +175,7 @@ static int _py_int__invert__(int argc, py_Ref argv) {
 }
 
 static int _py_int__bit_length(int argc, py_Ref argv) {
-    int64_t x = py_toint(&argv[0]);
+    int64_t x = py_toint(py_arg(0));
     if(x < 0) x = -x;
     int bits = 0;
     while(x) {

+ 2 - 2
src/interpreter/vm.c

@@ -58,8 +58,8 @@ void pk_VM__ctor(pk_VM* self){
     self->last_error = NULL;
     self->last_retval = PY_NULL;
 
-    self->__curr_class = NULL;
-    self->__cached_object_new = NULL;
+    self->__curr_class = PY_NULL;
+    self->__cached_object_new = PY_NULL;
     self->__dynamic_func_decl = NULL;
 
     pk_ManagedHeap__ctor(&self->heap, self);

+ 4 - 4
src/public/py_ops.c

@@ -15,14 +15,14 @@ int py_repr(const py_Ref val) {
     return py_callmethod(val, __repr__);
 }
 
-int py_getattr(const py_Ref self, py_Name name, py_Ref out){
-    return -1;
+bool py_getattr(const py_Ref self, py_Name name, py_Ref out){
+    return true;
 }
 
 int py_setattr(py_Ref self, py_Name name, const py_Ref val){
     return -1;
 }
 
-int py_callmethod(py_Ref self, py_Name name, ...){
+int py_delattr(py_Ref self, py_Name name){
     return -1;
-}
+}

+ 12 - 0
src/public/values.c

@@ -39,6 +39,18 @@ void py_newstrn(py_Ref out, const char* data, int size) {
     out->_obj = obj;
 }
 
+void py_newbytes(py_Ref out, const unsigned char* data, int size) {
+    pk_ManagedHeap* heap = &pk_current_vm->heap;
+    // 4 bytes size + data
+    PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_bytes, 0, sizeof(int) + size);
+    int* psize = (int*)PyObject__value(obj);
+    *psize = size;
+    memcpy(psize + 1, data, size);
+    out->type = tp_bytes;
+    out->is_ptr = true;
+    out->_obj = obj;
+}
+
 void py_newnone(py_Ref out) {
     pk_VM* vm = pk_current_vm;
     *out = vm->None;

+ 16 - 0
src/public/vm.c

@@ -45,4 +45,20 @@ int py_eval(const char* source, py_Ref out) {
         return 0;
     }
     PK_UNREACHABLE();
+}
+
+int py_call(py_Ref callable, ...){
+    return -1;
+}
+
+int py_callmethod(py_Ref self, py_Name name, ...){
+    return -1;
+}
+
+int py_vectorcall(int argc, int kwargc){
+    return -1;
+}
+
+bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self){
+    return -1;
 }