This commit is contained in:
blueloveTH 2023-01-05 17:23:05 +08:00
parent 0e56b25b0d
commit a4c2cc5605
4 changed files with 92 additions and 67 deletions

View File

@ -27,6 +27,44 @@ _Str pad(const _Str& s, const int n){
return s + std::string(n - s.size(), ' '); return s + std::string(n - s.size(), ' ');
} }
enum CodeBlockType {
NO_BLOCK,
FOR_LOOP,
CONTEXT_MANAGER,
TRY_EXCEPT,
};
struct CodeBlock {
CodeBlockType type;
std::vector<int> id;
int parent; // parent index in co_blocks
std::string toString() const {
if(parent == -1) return "";
std::string s = "[";
for(int i = 0; i < id.size(); i++){
s += std::to_string(id[i]);
if(i != id.size()-1) s += "-";
}
s += ": ";
s += std::to_string(type);
s += "]";
return s;
}
bool operator==(const std::vector<int>& other) const {
return id == other;
}
bool operator!=(const std::vector<int>& other) const {
return id != other;
}
int depth() const {
return id.size();
}
};
struct CodeObject { struct CodeObject {
_Source src; _Source src;
_Str name; _Str name;
@ -45,48 +83,32 @@ struct CodeObject {
std::vector<std::pair<_Str, NameScope>> co_names; std::vector<std::pair<_Str, NameScope>> co_names;
std::vector<_Str> co_global_names; std::vector<_Str> co_global_names;
std::vector<std::vector<int>> co_loops = {{}}; std::vector<CodeBlock> co_blocks = { CodeBlock{NO_BLOCK, {}, -1} };
int _currLoopIndex = 0;
std::string getBlockStr(int block){ // tmp variables
std::vector<int> loopId = co_loops[block]; int _currBlockIndex = 0;
std::string s = "";
for(int i=0; i<loopId.size(); i++){ void __enterBlock(CodeBlockType type){
s += std::to_string(loopId[i]); const CodeBlock& currBlock = co_blocks[_currBlockIndex];
if(i != loopId.size()-1) s += "-"; std::vector<int> copy(currBlock.id);
copy.push_back(-1);
int t = 0;
while(true){
copy[copy.size()-1] = t;
auto it = std::find(co_blocks.begin(), co_blocks.end(), copy);
if(it == co_blocks.end()) break;
t++;
} }
return s; co_blocks.push_back(CodeBlock{type, copy, _currBlockIndex});
_currBlockIndex = co_blocks.size()-1;
} }
void __enterLoop(int depth){ void __exitBlock(){
const std::vector<int>& prevLoopId = co_loops[_currLoopIndex]; _currBlockIndex = co_blocks[_currBlockIndex].parent;
if(depth - prevLoopId.size() == 1){ if(_currBlockIndex < 0) UNREACHABLE();
std::vector<int> copy = prevLoopId;
copy.push_back(0);
int t = 0;
while(true){
copy[copy.size()-1] = t;
auto it = std::find(co_loops.begin(), co_loops.end(), copy);
if(it == co_loops.end()) break;
t++;
}
co_loops.push_back(copy);
}else{
UNREACHABLE();
}
_currLoopIndex = co_loops.size()-1;
}
void __exitLoop(){
std::vector<int> copy = co_loops[_currLoopIndex];
copy.pop_back();
auto it = std::find(co_loops.begin(), co_loops.end(), copy);
if(it == co_loops.end()) UNREACHABLE();
_currLoopIndex = it - co_loops.begin();
} }
// for goto use // for goto use
// note: some opcodes moves the bytecode, such as listcomp
// goto/label should be put at toplevel statements // goto/label should be put at toplevel statements
emhash8::HashMap<_Str, int> co_labels; emhash8::HashMap<_Str, int> co_labels;
@ -125,7 +147,7 @@ public:
PyVar _module; PyVar _module;
PyVarDict f_locals; PyVarDict f_locals;
inline PyVarDict copy_f_locals(){ inline PyVarDict copy_f_locals() const {
return f_locals; return f_locals;
} }
@ -194,27 +216,25 @@ public:
this->ip += i; this->ip += i;
} }
void jumpAbsoluteSafe(int i){ void jumpAbsoluteSafe(int target){
const ByteCode& prev = code->co_code[this->ip]; const ByteCode& prev = code->co_code[this->ip];
const std::vector<int> prevLoopId = code->co_loops[prev.block]; int i = prev.block;
this->ip = i; this->ip = target;
if(isCodeEnd()){ if(isCodeEnd()){
for(int i=0; i<prevLoopId.size(); i++) __pop(); while(i>=0){
return; if(code->co_blocks[i].type == FOR_LOOP) __pop();
} i = code->co_blocks[i].parent;
const ByteCode& next = code->co_code[i];
const std::vector<int> nextLoopId = code->co_loops[next.block];
int sizeDelta = prevLoopId.size() - nextLoopId.size();
if(sizeDelta < 0){
throw std::runtime_error("invalid jump from " + code->getBlockStr(prev.block) + " to " + code->getBlockStr(next.block));
}else{
for(int i=0; i<nextLoopId.size(); i++){
if(nextLoopId[i] != prevLoopId[i]){
throw std::runtime_error("invalid jump from " + code->getBlockStr(prev.block) + " to " + code->getBlockStr(next.block));
}
} }
}else{
const ByteCode& next = code->co_code[target];
while(i>=0 && i!=next.block){
if(code->co_blocks[i].type == FOR_LOOP) __pop();
i = code->co_blocks[i].parent;
}
if(i!=next.block) throw std::runtime_error(
"invalid jump from " + code->co_blocks[prev.block].toString() + " to " + code->co_blocks[next.block].toString()
);
} }
for(int i=0; i<sizeDelta; i++) __pop();
} }
pkpy::ArgList popNValuesReversed(VM* vm, int n){ pkpy::ArgList popNValuesReversed(VM* vm, int n){

View File

@ -575,7 +575,7 @@ __LISTCOMP:
patchJump(_skipPatch); patchJump(_skipPatch);
emitCode(OP_GET_ITER); emitCode(OP_GET_ITER);
Loop& loop = enterLoop(); Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP);
int patch = emitCode(OP_FOR_ITER); int patch = emitCode(OP_FOR_ITER);
if(_cond_end_return != -1) { // there is an if condition if(_cond_end_return != -1) { // there is an if condition
@ -594,7 +594,7 @@ __LISTCOMP:
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
patchJump(patch); patchJump(patch);
exitLoop(); exitLoop(); getCode()->__exitBlock();
matchNewLines(mode()==SINGLE_MODE); matchNewLines(mode()==SINGLE_MODE);
consume(TK("]")); consume(TK("]"));
} }
@ -710,7 +710,7 @@ __LISTCOMP:
int emitCode(Opcode opcode, int arg=-1) { int emitCode(Opcode opcode, int arg=-1) {
int line = parser->previous.line; int line = parser->previous.line;
getCode()->co_code.push_back( getCode()->co_code.push_back(
ByteCode{(uint8_t)opcode, arg, (uint16_t)line, (uint16_t)getCode()->_currLoopIndex} ByteCode{(uint8_t)opcode, arg, (uint16_t)line, (uint16_t)getCode()->_currBlockIndex}
); );
return getCode()->co_code.size() - 1; return getCode()->co_code.size() - 1;
} }
@ -818,14 +818,12 @@ __LISTCOMP:
} }
Loop& enterLoop(){ Loop& enterLoop(){
getCode()->__enterLoop(loops.size()+1);
Loop lp((int)getCode()->co_code.size()); Loop lp((int)getCode()->co_code.size());
loops.push(lp); loops.push(lp);
return loops.top(); return loops.top();
} }
void exitLoop(){ void exitLoop(){
getCode()->__exitLoop();
Loop& lp = loops.top(); Loop& lp = loops.top();
for(int addr : lp.breaks) patchJump(addr); for(int addr : lp.breaks) patchJump(addr);
loops.pop(); loops.pop();
@ -851,14 +849,14 @@ __LISTCOMP:
} }
void compileForLoop() { void compileForLoop() {
EXPR_FOR_VARS();consume(TK("in"));EXPR_TUPLE(); EXPR_FOR_VARS();consume(TK("in")); EXPR_TUPLE();
emitCode(OP_GET_ITER); emitCode(OP_GET_ITER);
Loop& loop = enterLoop(); Loop& loop = enterLoop(); getCode()->__enterBlock(FOR_LOOP);
int patch = emitCode(OP_FOR_ITER); int patch = emitCode(OP_FOR_ITER);
compileBlockBody(); compileBlockBody();
emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine(); emitCode(OP_JUMP_ABSOLUTE, loop.start); keepOpcodeLine();
patchJump(patch); patchJump(patch);
exitLoop(); exitLoop(); getCode()->__exitBlock();
} }
void compileStatement() { void compileStatement() {

View File

@ -1,8 +1,15 @@
#ifdef OPCODE #ifdef OPCODE
// Do nothing
OPCODE(NO_OP) OPCODE(NO_OP)
// This op is a placeholder that should never be executed
OPCODE(DELETED_OP) OPCODE(DELETED_OP)
// Load a constant from the `co_consts`
// ARG: array index
OPCODE(LOAD_CONST) OPCODE(LOAD_CONST)
OPCODE(IMPORT_NAME) OPCODE(IMPORT_NAME)
OPCODE(PRINT_EXPR) OPCODE(PRINT_EXPR)
OPCODE(POP_TOP) OPCODE(POP_TOP)
@ -67,4 +74,6 @@ OPCODE(WITH_EXIT)
OPCODE(JUMP_RELATIVE) OPCODE(JUMP_RELATIVE)
OPCODE(RAISE_VARARGS)
#endif #endif

View File

@ -136,7 +136,6 @@ protected:
setAttr(fn, __module__, frame->_module); setAttr(fn, __module__, frame->_module);
setAttr(cls, f->name, fn); setAttr(cls, f->name, fn);
} }
// frame->f_globals()[clsName] = cls;
} break; } break;
case OP_RETURN_VALUE: return frame->popValue(this); case OP_RETURN_VALUE: return frame->popValue(this);
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
@ -548,9 +547,9 @@ public:
try { try {
_Code code = compile(source, filename, mode); _Code code = compile(source, filename, mode);
// if(filename != "<builtins>"){ if(filename != "<builtins>"){
// std::cout << disassemble(code) << std::endl; std::cout << disassemble(code) << std::endl;
// } }
return _exec(code, _module, {}); return _exec(code, _module, {});
}catch (const _Error& e){ }catch (const _Error& e){
@ -774,7 +773,6 @@ public:
int prev_line = -1; int prev_line = -1;
for(int i=0; i<code->co_code.size(); i++){ for(int i=0; i<code->co_code.size(); i++){
const ByteCode& byte = code->co_code[i]; const ByteCode& byte = code->co_code[i];
//if(byte.op == OP_NO_OP || byte.op == OP_DELETED_OP) continue;
_Str line = std::to_string(byte.line); _Str line = std::to_string(byte.line);
if(byte.line == prev_line) line = ""; if(byte.line == prev_line) line = "";
else{ else{
@ -784,7 +782,7 @@ public:
ss << pad(line, 12) << " " << pad(std::to_string(i), 3); ss << pad(line, 12) << " " << pad(std::to_string(i), 3);
ss << " " << pad(OP_NAMES[byte.op], 20) << " "; 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);
ss << '[' << code->getBlockStr(byte.block) << ']'; ss << code->co_blocks[byte.block].toString();
if(i != code->co_code.size() - 1) ss << '\n'; if(i != code->co_code.size() - 1) ss << '\n';
} }
_StrStream consts; _StrStream consts;