|
|
@@ -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();
|