This commit is contained in:
blueloveTH 2023-04-06 22:42:53 +08:00
parent c694e1e67d
commit 5d6d109164
7 changed files with 91 additions and 46 deletions

View File

@ -48,6 +48,7 @@ __NEXT_STEP:;
PyObject* obj = VAR(Function({decl, frame->_module, frame->_locals}));
frame->push(obj);
} DISPATCH();
case OP_LOAD_NULL: frame->push(_py_null); DISPATCH();
/*****************************************/
case OP_LOAD_NAME: {
StrName name = frame->co->names[byte.arg];
@ -67,6 +68,13 @@ __NEXT_STEP:;
StrName name = frame->co->names[byte.arg];
frame->top() = getattr(a, name);
} DISPATCH();
case OP_LOAD_METHOD: {
PyObject* a = frame->top();
StrName name = frame->co->names[byte.arg];
PyObject* self;
frame->top() = get_unbound_method(a, name, &self);
frame->push(self);
} DISPATCH();
case OP_LOAD_SUBSCR: {
Args args(2);
args[1] = frame->popx(); // b
@ -222,7 +230,13 @@ __NEXT_STEP:;
/*****************************************/
// TODO: examine this later
case OP_CALL: case OP_CALL_UNPACK: {
Args args = frame->popx_n_reversed(byte.arg);
int ARGC = byte.arg;
bool method_call = frame->top_n(ARGC) != _py_null;
if(method_call) ARGC++; // add self into args
Args args = frame->popx_n_reversed(ARGC);
if(!method_call) frame->pop();
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
PyObject* callable = frame->popx();
PyObject* ret = call(callable, std::move(args), no_arg(), true);
@ -233,7 +247,12 @@ __NEXT_STEP:;
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
Args kwargs = frame->popx_n_reversed(KWARGC*2);
bool method_call = frame->top_n(ARGC) != _py_null;
if(method_call) ARGC++; // add self into args
Args args = frame->popx_n_reversed(ARGC);
if(!method_call) frame->pop();
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
PyObject* callable = frame->popx();
PyObject* ret = call(callable, std::move(args), kwargs, true);

View File

@ -33,12 +33,12 @@
// debug macros
#define DEBUG_NO_BUILTIN_MODULES 0
#define DEBUG_EXTRA_CHECK 0
#define DEBUG_DIS_EXEC 1
#define DEBUG_DIS_EXEC 0
#define DEBUG_DIS_EXEC_MIN 1
#define DEBUG_CEVAL_STEP 0
#define DEBUG_FULL_EXCEPTION 0
#define DEBUG_NO_AUTO_GC 1
#define DEBUG_GC_STATS 0
#define DEBUG_GC_STATS 1
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
#define PK_ENABLE_FILEIO 0

View File

@ -884,6 +884,8 @@ __SUBSCR_END:
for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){
(*it)->emit(ctx());
ctx()->emit(OP_ROT_TWO, BC_NOARG, (*it)->line);
ctx()->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE);
ctx()->emit(OP_CALL, 1, (*it)->line);
}
if(!ctx()->is_compiling_class){

View File

@ -17,10 +17,10 @@ struct Expr{
virtual void emit(CodeEmitContext* ctx) = 0;
virtual Str str() const = 0;
virtual std::vector<const Expr*> children() const { return {}; }
virtual bool is_starred() const { return false; }
virtual bool is_literal() const { return false; }
virtual bool is_json_object() const { return false; }
virtual bool is_attrib() const { return false; }
// for OP_DELETE_XXX
virtual bool emit_del(CodeEmitContext* ctx) { return false; }
@ -163,8 +163,6 @@ struct StarredExpr: Expr{
StarredExpr(Expr_&& child): child(std::move(child)) {}
Str str() const override { return "*"; }
std::vector<const Expr*> children() const override { return {child.get()}; }
bool is_starred() const override { return true; }
void emit(CodeEmitContext* ctx) override {
@ -184,8 +182,6 @@ struct NotExpr: Expr{
NotExpr(Expr_&& child): child(std::move(child)) {}
Str str() const override { return "not"; }
std::vector<const Expr*> children() const override { return {child.get()}; }
void emit(CodeEmitContext* ctx) override {
child->emit(ctx);
ctx->emit(OP_UNARY_NOT, BC_NOARG, line);
@ -198,8 +194,6 @@ struct AndExpr: Expr{
Expr_ rhs;
Str str() const override { return "and"; }
std::vector<const Expr*> children() const override { return {lhs.get(), rhs.get()}; }
void emit(CodeEmitContext* ctx) override {
lhs->emit(ctx);
int patch = ctx->emit(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line);
@ -214,8 +208,6 @@ struct OrExpr: Expr{
Expr_ rhs;
Str str() const override { return "or"; }
std::vector<const Expr*> children() const override { return {lhs.get(), rhs.get()}; }
void emit(CodeEmitContext* ctx) override {
lhs->emit(ctx);
int patch = ctx->emit(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line);
@ -295,8 +287,6 @@ struct NegatedExpr: Expr{
NegatedExpr(Expr_&& child): child(std::move(child)) {}
Str str() const override { return "-"; }
std::vector<const Expr*> children() const override { return {child.get()}; }
void emit(CodeEmitContext* ctx) override {
VM* vm = ctx->vm;
// if child is a int of float, do constant folding
@ -330,11 +320,6 @@ struct SliceExpr: Expr{
Expr_ step;
Str str() const override { return "slice()"; }
std::vector<const Expr*> children() const override {
// may contain nullptr
return {start.get(), stop.get(), step.get()};
}
void emit(CodeEmitContext* ctx) override {
if(start){
start->emit(ctx);
@ -362,7 +347,6 @@ struct DictItemExpr: Expr{
Expr_ key;
Expr_ value;
Str str() const override { return "k:v"; }
std::vector<const Expr*> children() const override { return {key.get(), value.get()}; }
void emit(CodeEmitContext* ctx) override {
value->emit(ctx);
@ -376,12 +360,6 @@ struct SequenceExpr: Expr{
SequenceExpr(std::vector<Expr_>&& items): items(std::move(items)) {}
virtual Opcode opcode() const = 0;
std::vector<const Expr*> children() const override {
std::vector<const Expr*> ret;
for(auto& item: items) ret.push_back(item.get());
return ret;
}
void emit(CodeEmitContext* ctx) override {
for(auto& item: items) item->emit(ctx);
ctx->emit(opcode(), items.size(), line);
@ -543,6 +521,7 @@ struct FStringExpr: Expr{
size++;
}
ctx->emit(OP_LOAD_BUILTIN_EVAL, BC_NOARG, line);
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(m[1].str())), line);
ctx->emit(OP_CALL, 1, line);
size++;
@ -609,6 +588,14 @@ struct AttribExpr: Expr{
ctx->emit(OP_STORE_ATTR, index, line);
return true;
}
void emit_method(CodeEmitContext* ctx) {
a->emit(ctx);
int index = ctx->add_name(b);
ctx->emit(OP_LOAD_METHOD, index, line);
}
bool is_attrib() const override { return true; }
};
// PASS
@ -618,13 +605,6 @@ struct CallExpr: Expr{
std::vector<std::pair<Str, Expr_>> kwargs;
Str str() const override { return "call(...)"; }
std::vector<const Expr*> children() const override {
std::vector<const Expr*> ret;
for(auto& item: args) ret.push_back(item.get());
// ...ignore kwargs for simplicity
return ret;
}
bool need_unpack() const {
for(auto& item: args) if(item->is_starred()) return true;
return false;
@ -634,7 +614,13 @@ struct CallExpr: Expr{
VM* vm = ctx->vm;
// TODO: if callable is a AttrExpr, we should try to use `fast_call`
// instead of use `boundmethod` proxy
callable->emit(ctx);
if(callable->is_attrib()){
auto p = static_cast<AttribExpr*>(callable.get());
p->emit_method(ctx);
}else{
callable->emit(ctx);
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
}
// emit args
for(auto& item: args) item->emit(ctx);
// emit kwargs
@ -659,10 +645,6 @@ struct BinaryExpr: Expr{
Expr_ rhs;
Str str() const override { return TK_STR(op); }
std::vector<const Expr*> children() const override {
return {lhs.get(), rhs.get()};
}
void emit(CodeEmitContext* ctx) override {
lhs->emit(ctx);
rhs->emit(ctx);
@ -706,10 +688,6 @@ struct TernaryExpr: Expr{
return "cond ? t : f";
}
std::vector<const Expr*> children() const override {
return {cond.get(), true_expr.get(), false_expr.get()};
}
void emit(CodeEmitContext* ctx) override {
cond->emit(ctx);
int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);

View File

@ -15,9 +15,11 @@ OPCODE(LOAD_FALSE)
OPCODE(LOAD_ELLIPSIS)
OPCODE(LOAD_BUILTIN_EVAL)
OPCODE(LOAD_FUNCTION)
OPCODE(LOAD_NULL)
/**************************/
OPCODE(LOAD_NAME)
OPCODE(LOAD_ATTR)
OPCODE(LOAD_METHOD)
OPCODE(LOAD_SUBSCR)
OPCODE(STORE_LOCAL)

View File

@ -2,6 +2,7 @@
#include "ceval.h"
#include "compiler.h"
#include "obj.h"
#include "repl.h"
#include "iter.h"
#include "cffi.h"
@ -68,7 +69,9 @@ inline void init_builtins(VM* _vm) {
vm->check_type(args[0], vm->tp_type);
Type type = OBJ_GET(Type, args[0]);
if(!vm->isinstance(args[1], type)){
vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1])));
Str _1 = obj_type_name(vm, type);
vm->TypeError("super(): " + _0.escape(true) + " is not an instance of " + _1.escape(true));
}
Type base = vm->_all_types[type].base;
return vm->heap.gcnew(vm->tp_super, Super(args[1], base));

View File

@ -60,6 +60,7 @@ public:
PyObject* _py_op_call;
PyObject* _py_op_yield;
PyObject* _py_null;
PyObject* None;
PyObject* True;
PyObject* False;
@ -337,6 +338,7 @@ public:
PyObject* call(PyObject* callable, Args args, const Args& kwargs, bool opCall);
void unpack_args(Args& args);
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false);
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self);
template<typename T>
void setattr(PyObject* obj, StrName name, T&& value);
template<int ARGC>
@ -594,7 +596,7 @@ inline Str VM::disassemble(CodeObject_ co){
argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")";
break;
case OP_LOAD_NAME: case OP_STORE_LOCAL: case OP_STORE_GLOBAL:
case OP_LOAD_ATTR: case OP_STORE_ATTR: case OP_DELETE_ATTR:
case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
case OP_IMPORT_NAME: case OP_BEGIN_CLASS:
case OP_DELETE_LOCAL: case OP_DELETE_GLOBAL:
argStr += " (" + co->names[byte.arg].str().escape(true) + ")";
@ -663,6 +665,7 @@ inline void VM::init_builtin_types(){
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
this->True = heap._new<Dummy>(tp_bool, {});
this->False = heap._new<Dummy>(tp_bool, {});
this->_py_null = heap._new<Dummy>(_new_type_object("_py_null"), {});
this->_py_op_call = heap._new<Dummy>(_new_type_object("_py_op_call"), {});
this->_py_op_yield = heap._new<Dummy>(_new_type_object("_py_op_yield"), {});
@ -682,7 +685,6 @@ inline void VM::init_builtin_types(){
post_init();
for(int i=0; i<_all_types.size(); i++){
// std::cout << i << ": " << _all_types[i].name << std::endl;
_all_types[i].obj->attr()._try_perfect_rehash();
}
for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash();
@ -786,6 +788,7 @@ inline void VM::unpack_args(Args& args){
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
// TODO: class_only impl may not be correct
PyObject* objtype = _t(obj);
// handle super() proxy
if(is_type(obj, tp_super)){
@ -815,6 +818,39 @@ inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool c
return nullptr;
}
// used by OP_LOAD_METHOD
// try to load a unbound method (fallback to `getattr` if not found)
inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self){
*self = _py_null;
// TODO: class_only impl may not be correct
PyObject* objtype = _t(obj);
// handle super() proxy
if(is_type(obj, tp_super)){
const Super& super = OBJ_GET(Super, obj);
obj = super.first;
objtype = _t(super.second);
}
PyObject* cls_var = find_name_in_mro(objtype, name);
if(cls_var != nullptr){
// handle descriptor
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__);
if(descr_get != nullptr) return call(descr_get, Args{cls_var, obj});
}
// handle instance __dict__
if(!is_tagged(obj) && obj->is_attr_valid()){
PyObject* val = obj->attr().try_get(name);
if(val != nullptr) return val;
}
if(cls_var != nullptr){
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
*self = obj;
}
return cls_var;
}
AttributeError(obj, name);
return nullptr;
}
template<typename T>
inline void VM::setattr(PyObject* obj, StrName name, T&& value){
static_assert(std::is_same_v<std::decay_t<T>, PyObject*>);
@ -894,7 +930,12 @@ inline PyObject* VM::_exec(){
Exception& _e = CAST(Exception&, obj);
_e.st_push(frame->snapshot());
callstack.pop();
if(callstack.empty()) throw _e;
if(callstack.empty()){
#if DEBUG_FULL_EXCEPTION
std::cerr << _e.summary() << std::endl;
#endif
throw _e;
}
frame = callstack.top().get();
frame->push(obj);
if(frame->id < base_id) throw ToBeRaisedException();