This commit is contained in:
blueloveTH 2023-01-09 15:42:43 +08:00
parent 87ef4940c8
commit 9e7421a199
5 changed files with 93 additions and 20 deletions

View File

@ -24,6 +24,7 @@ struct ByteCode{
};
_Str pad(const _Str& s, const int n){
if(s.size() >= n) return s.substr(0, n);
return s + std::string(n - s.size(), ' ');
}
@ -50,7 +51,7 @@ struct CodeBlock {
s += std::to_string(id[i]);
if(i != id.size()-1) s += "-";
}
s += ": ";
s += ": type=";
s += std::to_string(type);
s += "]";
return s;
@ -146,7 +147,38 @@ struct CodeObject {
}
void optimize_level_1(){
for(int i=0; i<co_code.size(); i++){
if(co_code[i].op >= OP_BINARY_OP && co_code[i].op <= OP_CONTAINS_OP){
for(int j=0; j<2; j++){
ByteCode& bc = co_code[i-j-1];
if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){
if(bc.op == OP_LOAD_NAME_REF){
bc.op = OP_LOAD_NAME;
}
}else{
break;
}
}
}else if(co_code[i].op == OP_CALL){
int ARGC = co_code[i].arg & 0xFFFF;
int KWARGC = (co_code[i].arg >> 16) & 0xFFFF;
if(KWARGC != 0) continue;
for(int j=0; j<ARGC+1; j++){
ByteCode& bc = co_code[i-j-1];
if(bc.op >= OP_LOAD_CONST && bc.op <= OP_LOAD_NAME_REF){
if(bc.op == OP_LOAD_NAME_REF){
bc.op = OP_LOAD_NAME;
}
}else{
break;
}
}
}
}
}
void optimize(int level=1){
optimize_level_1();
}
};

View File

@ -415,6 +415,7 @@ public:
this->codes.push(func->code);
EXPR_TUPLE();
emitCode(OP_RETURN_VALUE);
func->code->optimize();
this->codes.pop();
emitCode(OP_LOAD_LAMBDA, getCode()->addConst(vm->PyFunction(func)));
}
@ -1021,6 +1022,7 @@ __LISTCOMP:
func->code = pkpy::make_shared<CodeObject>(parser->src, func->name);
this->codes.push(func->code);
compileBlockBody();
func->code->optimize();
this->codes.pop();
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyFunction(func)));
if(!isCompilingClass) emitCode(OP_STORE_FUNCTION);
@ -1072,6 +1074,7 @@ __LISTCOMP:
if(mode()==EVAL_MODE) {
EXPR_TUPLE();
consume(TK("@eof"));
code->optimize();
return code;
}else if(mode()==JSON_MODE){
PyVarOrNull value = readLiteral();
@ -1080,13 +1083,14 @@ __LISTCOMP:
else if(match(TK("["))) exprList();
else syntaxError("expect a JSON object or array");
consume(TK("@eof"));
return code;
return code; // no need to optimize for JSON decoding
}
while (!match(TK("@eof"))) {
compileTopLevelStatement();
matchNewLines();
}
code->optimize();
return code;
}

View File

@ -1,15 +1,8 @@
#ifdef OPCODE
// Do nothing
OPCODE(NO_OP)
// This op is a placeholder that should never be executed
OPCODE(DELETED_OP)
// Load a constant from the `co_consts`
// ARG: array index
OPCODE(LOAD_CONST)
OPCODE(IMPORT_NAME)
OPCODE(PRINT_EXPR)
OPCODE(POP_TOP)
@ -43,21 +36,21 @@ OPCODE(SAFE_JUMP_ABSOLUTE)
OPCODE(JUMP_IF_TRUE_OR_POP)
OPCODE(JUMP_IF_FALSE_OR_POP)
// non-standard python opcodes
OPCODE(LOAD_CONST)
OPCODE(LOAD_NONE)
OPCODE(LOAD_TRUE)
OPCODE(LOAD_FALSE)
OPCODE(LOAD_EVAL_FN) // load eval() callable into stack
OPCODE(LOAD_LAMBDA) // LOAD_CONST + set __module__ attr
OPCODE(LOAD_EVAL_FN)
OPCODE(LOAD_LAMBDA)
OPCODE(LOAD_ELLIPSIS)
OPCODE(LOAD_NAME)
OPCODE(LOAD_NAME_REF) // no arg
OPCODE(ASSERT)
OPCODE(RAISE_ERROR)
OPCODE(STORE_FUNCTION)
OPCODE(BUILD_CLASS)
OPCODE(LOAD_NAME_REF) // no arg
OPCODE(BUILD_ATTR_REF) // arg for the name_ptr, [ptr, name_ptr] -> (*ptr).name_ptr
OPCODE(BUILD_INDEX_REF) // no arg, [ptr, expr] -> (*ptr)[expr]
OPCODE(STORE_NAME_REF) // arg for the name_ptr, [expr], directly store to the name_ptr without pushing it to the stack

View File

@ -124,6 +124,13 @@ void __initializeBuiltinFunctions(VM* _vm) {
return obj;
});
_vm->bindBuiltinFunc("hex", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1);
std::stringstream ss;
ss << std::hex << vm->PyInt_AS_C(args[0]);
return vm->PyStr("0x" + ss.str());
});
_vm->bindBuiltinFunc("dir", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1);
std::vector<_Str> names;
@ -142,7 +149,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindMethod("object", "__repr__", [](VM* vm, const pkpy::ArgList& args) {
PyVar _self = args[0];
_Str s = "<" + UNION_TP_NAME(_self) + " object at " + std::to_string((uintptr_t)_self.get()) + ">";
std::stringstream ss;
ss << std::hex << (uintptr_t)_self.get();
_Str s = "<" + UNION_TP_NAME(_self) + " object at 0x" + ss.str() + ">";
return vm->PyStr(s);
});

View File

@ -56,6 +56,9 @@ protected:
case OP_LOAD_NAME_REF: {
frame->push(PyRef(NameRef(frame->code->co_names[byte.arg])));
} break;
case OP_LOAD_NAME: {
frame->push(NameRef(frame->code->co_names[byte.arg]).get(this, frame));
} break;
case OP_STORE_NAME_REF: {
const auto& p = frame->code->co_names[byte.arg];
NameRef(p).set(this, frame, frame->popValue(this));
@ -555,11 +558,12 @@ public:
if(_module == nullptr) _module = _main;
try {
_Code code = compile(source, filename, mode);
if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
//if(filename != "<builtins>") std::cout << disassemble(code) << std::endl;
return _exec(code, _module, {});
}catch (const _Error& e){
*_stderr << e.what() << '\n';
}catch (const std::exception& e) {
}
catch (const std::exception& e) {
auto re = RuntimeError("UnexpectedError", e.what(), _cleanErrorAndGetSnapshots());
*_stderr << re.what() << '\n';
}
@ -759,7 +763,15 @@ public:
}
_Str disassemble(_Code code){
std::vector<int> jumpTargets;
for(auto byte : code->co_code){
if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_SAFE_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE){
jumpTargets.push_back(byte.arg);
}
}
_StrStream ss;
ss << std::string(54, '-') << '\n';
ss << code->name << ":\n";
int prev_line = -1;
for(int i=0; i<code->co_code.size(); i++){
const ByteCode& byte = code->co_code[i];
@ -769,9 +781,24 @@ public:
if(prev_line != -1) ss << "\n";
prev_line = byte.line;
}
ss << pad(line, 12) << " " << pad(std::to_string(i), 3);
std::string pointer;
if(std::find(jumpTargets.begin(), jumpTargets.end(), i) != jumpTargets.end()){
pointer = "-> ";
}else{
pointer = " ";
}
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
ss << " " << pad(OP_NAMES[byte.op], 20) << " ";
ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
// ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
std::string argStr = byte.arg == -1 ? "" : std::to_string(byte.arg);
if(byte.op == OP_LOAD_CONST){
argStr += " (" + PyStr_AS_C(asRepr(code->co_consts[byte.arg])) + ")";
}
if(byte.op == OP_LOAD_NAME_REF || byte.op == OP_LOAD_NAME){
argStr += " (" + code->co_names[byte.arg].first.__escape(true) + ")";
}
ss << pad(argStr, 20); // may overflow
ss << code->co_blocks[byte.block].toString();
if(i != code->co_code.size() - 1) ss << '\n';
}
@ -787,6 +814,14 @@ public:
}
names << PyStr_AS_C(asRepr(PyList(list)));
ss << '\n' << consts.str() << '\n' << names.str() << '\n';
for(int i=0; i<code->co_consts.size(); i++){
PyVar obj = code->co_consts[i];
if(obj->isType(_tp_function)){
const auto& f = PyFunction_AS_C(obj);
ss << disassemble(f->code);
}
}
return _Str(ss.str());
}