mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 13:00:17 +00:00
use relative jump
This commit is contained in:
parent
2868a955bb
commit
ea8dd3f0e8
@ -17,6 +17,15 @@ enum Opcode: uint8_t {
|
|||||||
struct Bytecode{
|
struct Bytecode{
|
||||||
uint8_t op;
|
uint8_t op;
|
||||||
uint16_t arg;
|
uint16_t arg;
|
||||||
|
|
||||||
|
void set_signed_arg(int arg){
|
||||||
|
if(arg < INT16_MIN || arg > INT16_MAX) throw std::runtime_error("byte.arg overflow");
|
||||||
|
this->arg = (int16_t)arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_forward_jump() const{
|
||||||
|
return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CodeBlockType {
|
enum class CodeBlockType {
|
||||||
|
@ -93,7 +93,7 @@ struct CodeEmitContext{
|
|||||||
std::set<Str> global_names;
|
std::set<Str> global_names;
|
||||||
CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {}
|
CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {}
|
||||||
|
|
||||||
int curr_block_i = 0;
|
int curr_iblock = 0;
|
||||||
bool is_compiling_class = false;
|
bool is_compiling_class = false;
|
||||||
int base_stack_size = 0;
|
int base_stack_size = 0;
|
||||||
|
|
||||||
|
@ -87,8 +87,7 @@ OPCODE(IS_OP)
|
|||||||
OPCODE(IS_NOT_OP)
|
OPCODE(IS_NOT_OP)
|
||||||
OPCODE(CONTAINS_OP)
|
OPCODE(CONTAINS_OP)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(JUMP_ABSOLUTE)
|
OPCODE(JUMP_FORWARD)
|
||||||
OPCODE(JUMP_ABSOLUTE_TOP)
|
|
||||||
OPCODE(POP_JUMP_IF_FALSE)
|
OPCODE(POP_JUMP_IF_FALSE)
|
||||||
OPCODE(POP_JUMP_IF_TRUE)
|
OPCODE(POP_JUMP_IF_TRUE)
|
||||||
OPCODE(JUMP_IF_TRUE_OR_POP)
|
OPCODE(JUMP_IF_TRUE_OR_POP)
|
||||||
@ -96,6 +95,8 @@ OPCODE(JUMP_IF_FALSE_OR_POP)
|
|||||||
OPCODE(SHORTCUT_IF_FALSE_OR_POP)
|
OPCODE(SHORTCUT_IF_FALSE_OR_POP)
|
||||||
OPCODE(LOOP_CONTINUE)
|
OPCODE(LOOP_CONTINUE)
|
||||||
OPCODE(LOOP_BREAK)
|
OPCODE(LOOP_BREAK)
|
||||||
|
/***/
|
||||||
|
OPCODE(JUMP_ABSOLUTE_TOP)
|
||||||
OPCODE(GOTO)
|
OPCODE(GOTO)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(FSTRING_EVAL)
|
OPCODE(FSTRING_EVAL)
|
||||||
|
@ -407,6 +407,7 @@ public:
|
|||||||
PyVar _t(PyVar obj){ return _all_types[_tp(obj)].obj; }
|
PyVar _t(PyVar obj){ return _all_types[_tp(obj)].obj; }
|
||||||
PyVar _t(Type type){ return _all_types[type].obj; }
|
PyVar _t(Type type){ return _all_types[type].obj; }
|
||||||
|
|
||||||
|
// equivalent to `obj == NotImplemented` but faster
|
||||||
static bool is_not_implemented(PyVar obj){ return obj.type == tp_not_implemented; }
|
static bool is_not_implemented(PyVar obj){ return obj.type == tp_not_implemented; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -95,7 +95,8 @@ bool VM::py_ge(PyVar _0, PyVar _1){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DISPATCH() { frame->_ip++; goto __NEXT_STEP; }
|
#define DISPATCH() { frame->_ip++; goto __NEXT_STEP; }
|
||||||
#define DISPATCH_JUMP(__target) { frame->_ip=co_codes+__target; goto __NEXT_STEP; }
|
#define DISPATCH_JUMP(__offset) { frame->_ip+=__offset; goto __NEXT_STEP; }
|
||||||
|
#define DISPATCH_JUMP_ABSOLUTE(__target) { frame->_ip=co_codes+__target; goto __NEXT_STEP; }
|
||||||
|
|
||||||
PyVar VM::__run_top_frame(){
|
PyVar VM::__run_top_frame(){
|
||||||
Frame* frame = &callstack.top();
|
Frame* frame = &callstack.top();
|
||||||
@ -638,26 +639,24 @@ __NEXT_STEP:
|
|||||||
TOP() = VAR(static_cast<bool>((int)CAST(bool, _0) ^ byte.arg));
|
TOP() = VAR(static_cast<bool>((int)CAST(bool, _0) ^ byte.arg));
|
||||||
} DISPATCH()
|
} DISPATCH()
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_JUMP_ABSOLUTE:
|
case OP_JUMP_FORWARD:
|
||||||
DISPATCH_JUMP(byte.arg)
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
case OP_JUMP_ABSOLUTE_TOP:
|
|
||||||
DISPATCH_JUMP(_CAST(int, POPX()))
|
|
||||||
case OP_POP_JUMP_IF_FALSE:
|
case OP_POP_JUMP_IF_FALSE:
|
||||||
if(!py_bool(POPX())) DISPATCH_JUMP(byte.arg)
|
if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_POP_JUMP_IF_TRUE:
|
case OP_POP_JUMP_IF_TRUE:
|
||||||
if(py_bool(POPX())) DISPATCH_JUMP(byte.arg)
|
if(py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_JUMP_IF_TRUE_OR_POP:
|
case OP_JUMP_IF_TRUE_OR_POP:
|
||||||
if(py_bool(TOP())){
|
if(py_bool(TOP())){
|
||||||
DISPATCH_JUMP(byte.arg)
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
}else{
|
}else{
|
||||||
POP();
|
POP();
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
}
|
}
|
||||||
case OP_JUMP_IF_FALSE_OR_POP:
|
case OP_JUMP_IF_FALSE_OR_POP:
|
||||||
if(!py_bool(TOP())){
|
if(!py_bool(TOP())){
|
||||||
DISPATCH_JUMP(byte.arg)
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
}else{
|
}else{
|
||||||
POP();
|
POP();
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -666,22 +665,26 @@ __NEXT_STEP:
|
|||||||
if(!py_bool(TOP())){ // [b, False]
|
if(!py_bool(TOP())){ // [b, False]
|
||||||
STACK_SHRINK(2); // []
|
STACK_SHRINK(2); // []
|
||||||
PUSH(vm->False); // [False]
|
PUSH(vm->False); // [False]
|
||||||
DISPATCH_JUMP(byte.arg)
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
} else{
|
} else{
|
||||||
POP(); // [b]
|
POP(); // [b]
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
}
|
}
|
||||||
case OP_LOOP_CONTINUE:
|
case OP_LOOP_CONTINUE:
|
||||||
DISPATCH_JUMP(byte.arg)
|
// just an alias of OP_JUMP_FORWARD
|
||||||
case OP_LOOP_BREAK:
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
frame->prepare_jump_break(&s_data, byte.arg);
|
case OP_LOOP_BREAK: {
|
||||||
DISPATCH_JUMP(byte.arg)
|
frame->prepare_jump_break(&s_data, frame->ip()+byte.arg);
|
||||||
|
DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
|
}
|
||||||
|
case OP_JUMP_ABSOLUTE_TOP:
|
||||||
|
DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX()))
|
||||||
case OP_GOTO: {
|
case OP_GOTO: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
int target = frame->co->labels.try_get_likely_found(_name);
|
int target = frame->co->labels.try_get_likely_found(_name);
|
||||||
if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
|
if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
|
||||||
frame->prepare_jump_break(&s_data, target);
|
frame->prepare_jump_break(&s_data, target);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}
|
}
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_FSTRING_EVAL:{
|
case OP_FSTRING_EVAL:{
|
||||||
@ -803,7 +806,7 @@ __NEXT_STEP:
|
|||||||
PyVar _0 = py_next(TOP());
|
PyVar _0 = py_next(TOP());
|
||||||
if(_0 == StopIteration){
|
if(_0 == StopIteration){
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
} else{
|
} else{
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -813,7 +816,7 @@ __NEXT_STEP:
|
|||||||
PyVar _0 = py_next(TOP());
|
PyVar _0 = py_next(TOP());
|
||||||
if(_0 == StopIteration){
|
if(_0 == StopIteration){
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}else{
|
}else{
|
||||||
frame->_locals[byte.arg] = _0;
|
frame->_locals[byte.arg] = _0;
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -823,7 +826,7 @@ __NEXT_STEP:
|
|||||||
PyVar _0 = py_next(TOP());
|
PyVar _0 = py_next(TOP());
|
||||||
if(_0 == StopIteration){
|
if(_0 == StopIteration){
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}else{
|
}else{
|
||||||
frame->f_globals().set(StrName(byte.arg), _0);
|
frame->f_globals().set(StrName(byte.arg), _0);
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -833,7 +836,7 @@ __NEXT_STEP:
|
|||||||
PyVar _0 = py_next(TOP());
|
PyVar _0 = py_next(TOP());
|
||||||
if(_0 == StopIteration){
|
if(_0 == StopIteration){
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}else{
|
}else{
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
return PY_OP_YIELD;
|
return PY_OP_YIELD;
|
||||||
@ -847,7 +850,7 @@ __NEXT_STEP:
|
|||||||
if(n == 0){
|
if(n == 0){
|
||||||
// StopIteration
|
// StopIteration
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}else if(n == 1){
|
}else if(n == 1){
|
||||||
// UNPACK_SEQUENCE
|
// UNPACK_SEQUENCE
|
||||||
__op_unpack_sequence(byte.arg);
|
__op_unpack_sequence(byte.arg);
|
||||||
@ -865,7 +868,7 @@ __NEXT_STEP:
|
|||||||
__op_unpack_sequence(byte.arg);
|
__op_unpack_sequence(byte.arg);
|
||||||
}else{
|
}else{
|
||||||
int target = frame->prepare_loop_break(&s_data);
|
int target = frame->prepare_loop_break(&s_data);
|
||||||
DISPATCH_JUMP(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} DISPATCH()
|
} DISPATCH()
|
||||||
|
@ -47,17 +47,13 @@ namespace pkpy{
|
|||||||
if(ctx()->co->consts.size() > 65530){
|
if(ctx()->co->consts.size() > 65530){
|
||||||
SyntaxError("maximum number of constants exceeded");
|
SyntaxError("maximum number of constants exceeded");
|
||||||
}
|
}
|
||||||
if(codes.size() > 65530 && ctx()->co->src->mode != JSON_MODE){
|
|
||||||
// json mode does not contain jump instructions, so it is safe to ignore this check
|
|
||||||
SyntaxError("maximum number of opcodes exceeded");
|
|
||||||
}
|
|
||||||
// pre-compute LOOP_BREAK and LOOP_CONTINUE
|
// pre-compute LOOP_BREAK and LOOP_CONTINUE
|
||||||
for(int i=0; i<codes.size(); i++){
|
for(int i=0; i<codes.size(); i++){
|
||||||
Bytecode& bc = codes[i];
|
Bytecode& bc = codes[i];
|
||||||
if(bc.op == OP_LOOP_CONTINUE){
|
if(bc.op == OP_LOOP_CONTINUE){
|
||||||
bc.arg = ctx()->co->blocks[bc.arg].start;
|
bc.set_signed_arg(ctx()->co->blocks[bc.arg].start - i);
|
||||||
}else if(bc.op == OP_LOOP_BREAK){
|
}else if(bc.op == OP_LOOP_BREAK){
|
||||||
bc.arg = ctx()->co->blocks[bc.arg].get_break_end();
|
bc.set_signed_arg(ctx()->co->blocks[bc.arg].get_break_end() - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// pre-compute func->is_simple
|
// pre-compute func->is_simple
|
||||||
@ -655,12 +651,12 @@ __EAT_DOTS_END:
|
|||||||
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
int patch = ctx()->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, prev().line);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
if (match(TK("elif"))) {
|
if (match(TK("elif"))) {
|
||||||
int exit_patch = ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, prev().line);
|
int exit_patch = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, prev().line);
|
||||||
ctx()->patch_jump(patch);
|
ctx()->patch_jump(patch);
|
||||||
compile_if_stmt();
|
compile_if_stmt();
|
||||||
ctx()->patch_jump(exit_patch);
|
ctx()->patch_jump(exit_patch);
|
||||||
} else if (match(TK("else"))) {
|
} else if (match(TK("else"))) {
|
||||||
int exit_patch = ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, prev().line);
|
int exit_patch = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, prev().line);
|
||||||
ctx()->patch_jump(patch);
|
ctx()->patch_jump(patch);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->patch_jump(exit_patch);
|
ctx()->patch_jump(exit_patch);
|
||||||
@ -691,7 +687,7 @@ __EAT_DOTS_END:
|
|||||||
EXPR_TUPLE(); ctx()->emit_expr();
|
EXPR_TUPLE(); ctx()->emit_expr();
|
||||||
ctx()->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
||||||
int for_codei = ctx()->emit_(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
|
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
||||||
bool ok = vars->emit_store(ctx());
|
bool ok = vars->emit_store(ctx());
|
||||||
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
||||||
ctx()->try_merge_for_iter_store(for_codei);
|
ctx()->try_merge_for_iter_store(for_codei);
|
||||||
@ -710,7 +706,7 @@ __EAT_DOTS_END:
|
|||||||
compile_block_body();
|
compile_block_body();
|
||||||
small_vector_2<int, 6> patches;
|
small_vector_2<int, 6> patches;
|
||||||
patches.push_back(
|
patches.push_back(
|
||||||
ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
|
ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE)
|
||||||
);
|
);
|
||||||
ctx()->exit_block();
|
ctx()->exit_block();
|
||||||
|
|
||||||
@ -739,13 +735,13 @@ __EAT_DOTS_END:
|
|||||||
// pop the exception
|
// pop the exception
|
||||||
ctx()->emit_(OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_POP_EXCEPTION, BC_NOARG, BC_KEEPLINE);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
patches.push_back(ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE));
|
patches.push_back(ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE));
|
||||||
ctx()->patch_jump(patch);
|
ctx()->patch_jump(patch);
|
||||||
}while(curr().type == TK("except"));
|
}while(curr().type == TK("except"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(match(TK("finally"))){
|
if(match(TK("finally"))){
|
||||||
int patch = ctx()->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE);
|
int patch = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
finally_entry = ctx()->co->codes.size();
|
finally_entry = ctx()->co->codes.size();
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->emit_(OP_JUMP_ABSOLUTE_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_JUMP_ABSOLUTE_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -755,7 +751,8 @@ __EAT_DOTS_END:
|
|||||||
if(finally_entry != -1){
|
if(finally_entry != -1){
|
||||||
i64 target = ctx()->co->codes.size()+2;
|
i64 target = ctx()->co->codes.size()+2;
|
||||||
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
||||||
ctx()->emit_(OP_JUMP_ABSOLUTE, finally_entry, BC_KEEPLINE);
|
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
|
ctx()->co->codes[i].set_signed_arg(finally_entry - i);
|
||||||
}
|
}
|
||||||
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
||||||
|
|
||||||
@ -764,7 +761,8 @@ __EAT_DOTS_END:
|
|||||||
if(finally_entry != -1){
|
if(finally_entry != -1){
|
||||||
i64 target = ctx()->co->codes.size()+2;
|
i64 target = ctx()->co->codes.size()+2;
|
||||||
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
||||||
ctx()->emit_(OP_JUMP_ABSOLUTE, finally_entry, BC_KEEPLINE);
|
int i = ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE);
|
||||||
|
ctx()->co->codes[i].set_signed_arg(finally_entry - i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
src/expr.cpp
27
src/expr.cpp
@ -14,7 +14,7 @@ namespace pkpy{
|
|||||||
}
|
}
|
||||||
|
|
||||||
int CodeEmitContext::get_loop() const {
|
int CodeEmitContext::get_loop() const {
|
||||||
int index = curr_block_i;
|
int index = curr_iblock;
|
||||||
while(index >= 0){
|
while(index >= 0){
|
||||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
|
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
|
||||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
|
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
|
||||||
@ -26,18 +26,18 @@ namespace pkpy{
|
|||||||
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type){
|
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type){
|
||||||
if(type==CodeBlockType::FOR_LOOP || type==CodeBlockType::CONTEXT_MANAGER) base_stack_size++;
|
if(type==CodeBlockType::FOR_LOOP || type==CodeBlockType::CONTEXT_MANAGER) base_stack_size++;
|
||||||
co->blocks.push_back(CodeBlock(
|
co->blocks.push_back(CodeBlock(
|
||||||
type, curr_block_i, base_stack_size, (int)co->codes.size()
|
type, curr_iblock, base_stack_size, (int)co->codes.size()
|
||||||
));
|
));
|
||||||
curr_block_i = co->blocks.size()-1;
|
curr_iblock = co->blocks.size()-1;
|
||||||
return &co->blocks[curr_block_i];
|
return &co->blocks[curr_iblock];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEmitContext::exit_block(){
|
void CodeEmitContext::exit_block(){
|
||||||
auto curr_type = co->blocks[curr_block_i].type;
|
auto curr_type = co->blocks[curr_iblock].type;
|
||||||
if(curr_type == CodeBlockType::FOR_LOOP || curr_type==CodeBlockType::CONTEXT_MANAGER) base_stack_size--;
|
if(curr_type == CodeBlockType::FOR_LOOP || curr_type==CodeBlockType::CONTEXT_MANAGER) base_stack_size--;
|
||||||
co->blocks[curr_block_i].end = co->codes.size();
|
co->blocks[curr_iblock].end = co->codes.size();
|
||||||
curr_block_i = co->blocks[curr_block_i].parent;
|
curr_iblock = co->blocks[curr_iblock].parent;
|
||||||
if(curr_block_i < 0) PK_FATAL_ERROR();
|
if(curr_iblock < 0) PK_FATAL_ERROR();
|
||||||
|
|
||||||
if(curr_type == CodeBlockType::FOR_LOOP){
|
if(curr_type == CodeBlockType::FOR_LOOP){
|
||||||
// add a no op here to make block check work
|
// add a no op here to make block check work
|
||||||
@ -54,7 +54,7 @@ namespace pkpy{
|
|||||||
|
|
||||||
int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
||||||
co->codes.push_back(Bytecode{(uint8_t)opcode, arg});
|
co->codes.push_back(Bytecode{(uint8_t)opcode, arg});
|
||||||
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_block_i});
|
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
|
||||||
int i = co->codes.size() - 1;
|
int i = co->codes.size() - 1;
|
||||||
if(line == BC_KEEPLINE){
|
if(line == BC_KEEPLINE){
|
||||||
if(i >= 1) co->lines[i].lineno = co->lines[i-1].lineno;
|
if(i >= 1) co->lines[i].lineno = co->lines[i-1].lineno;
|
||||||
@ -97,7 +97,7 @@ namespace pkpy{
|
|||||||
|
|
||||||
void CodeEmitContext::patch_jump(int index) {
|
void CodeEmitContext::patch_jump(int index) {
|
||||||
int target = co->codes.size();
|
int target = co->codes.size();
|
||||||
co->codes[index].arg = target;
|
co->codes[index].set_signed_arg(target-index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeEmitContext::add_label(StrName name){
|
bool CodeEmitContext::add_label(StrName name){
|
||||||
@ -399,7 +399,8 @@ namespace pkpy{
|
|||||||
iter->emit_(ctx);
|
iter->emit_(ctx);
|
||||||
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||||
ctx->enter_block(CodeBlockType::FOR_LOOP);
|
ctx->enter_block(CodeBlockType::FOR_LOOP);
|
||||||
int for_codei = ctx->emit_(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE);
|
int curr_iblock = ctx->curr_iblock;
|
||||||
|
int for_codei = ctx->emit_(OP_FOR_ITER, curr_iblock, BC_KEEPLINE);
|
||||||
bool ok = vars->emit_store(ctx);
|
bool ok = vars->emit_store(ctx);
|
||||||
// this error occurs in `vars` instead of this line, but...nevermind
|
// this error occurs in `vars` instead of this line, but...nevermind
|
||||||
if(!ok) throw std::runtime_error("SyntaxError");
|
if(!ok) throw std::runtime_error("SyntaxError");
|
||||||
@ -414,7 +415,7 @@ namespace pkpy{
|
|||||||
expr->emit_(ctx);
|
expr->emit_(ctx);
|
||||||
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
|
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
ctx->emit_(OP_LOOP_CONTINUE, ctx->get_loop(), BC_KEEPLINE);
|
ctx->emit_(OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
|
||||||
ctx->exit_block();
|
ctx->exit_block();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,7 +730,7 @@ namespace pkpy{
|
|||||||
cond->emit_(ctx);
|
cond->emit_(ctx);
|
||||||
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);
|
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);
|
||||||
true_expr->emit_(ctx);
|
true_expr->emit_(ctx);
|
||||||
int patch_2 = ctx->emit_(OP_JUMP_ABSOLUTE, BC_NOARG, true_expr->line);
|
int patch_2 = ctx->emit_(OP_JUMP_FORWARD, BC_NOARG, true_expr->line);
|
||||||
ctx->patch_jump(patch);
|
ctx->patch_jump(patch);
|
||||||
false_expr->emit_(ctx);
|
false_expr->emit_(ctx);
|
||||||
ctx->patch_jump(patch_2);
|
ctx->patch_jump(patch_2);
|
||||||
|
42
src/vm.cpp
42
src/vm.cpp
@ -710,29 +710,34 @@ PyVar VM::new_module(Str name, Str package) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string _opcode_argstr(VM* vm, Bytecode byte, const CodeObject* co){
|
static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject* co){
|
||||||
std::string argStr = std::to_string(byte.arg);
|
SStream ss;
|
||||||
|
if(byte.is_forward_jump()){
|
||||||
|
std::string argStr = std::to_string((int16_t)byte.arg);
|
||||||
|
ss << (i64)(int16_t)byte.arg;
|
||||||
|
ss << " (to " << (i64)((int16_t)byte.arg + i) << ")";
|
||||||
|
return ss.str().str();
|
||||||
|
}
|
||||||
|
ss << (i64)byte.arg;
|
||||||
switch(byte.op){
|
switch(byte.op){
|
||||||
case OP_LOAD_CONST: case OP_FORMAT_STRING: case OP_IMPORT_PATH:
|
case OP_LOAD_CONST: case OP_FORMAT_STRING: case OP_IMPORT_PATH:
|
||||||
if(vm != nullptr){
|
if(vm != nullptr) ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")";
|
||||||
argStr += _S(" (", vm->py_repr(co->consts[byte.arg]), ")").sv();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL:
|
case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL:
|
||||||
case OP_LOAD_ATTR: case OP_LOAD_METHOD: 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_BEGIN_CLASS: case OP_GOTO:
|
case OP_BEGIN_CLASS: case OP_GOTO:
|
||||||
case OP_DELETE_GLOBAL: case OP_INC_GLOBAL: case OP_DEC_GLOBAL: case OP_STORE_CLASS_ATTR: case OP_FOR_ITER_STORE_GLOBAL:
|
case OP_DELETE_GLOBAL: case OP_INC_GLOBAL: case OP_DEC_GLOBAL: case OP_STORE_CLASS_ATTR: case OP_FOR_ITER_STORE_GLOBAL:
|
||||||
argStr += _S(" (", StrName(byte.arg).sv(), ")").sv();
|
ss << " (" << StrName(byte.arg).sv() << ")";
|
||||||
break;
|
break;
|
||||||
case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: case OP_INC_FAST: case OP_DEC_FAST:
|
case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: case OP_INC_FAST: case OP_DEC_FAST:
|
||||||
case OP_FOR_ITER_STORE_FAST: case OP_LOAD_SUBSCR_FAST: case OP_STORE_SUBSCR_FAST:
|
case OP_FOR_ITER_STORE_FAST: case OP_LOAD_SUBSCR_FAST: case OP_STORE_SUBSCR_FAST:
|
||||||
argStr += _S(" (", co->varnames[byte.arg].sv(), ")").sv();
|
ss << " (" << co->varnames[byte.arg].sv() << ")";
|
||||||
break;
|
break;
|
||||||
case OP_LOAD_FUNCTION:
|
case OP_LOAD_FUNCTION:
|
||||||
argStr += _S(" (", co->func_decls[byte.arg]->code->name, ")").sv();
|
ss << " (" << co->func_decls[byte.arg]->code->name << ")";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return argStr;
|
return ss.str().str();
|
||||||
}
|
}
|
||||||
|
|
||||||
Str VM::disassemble(CodeObject_ co){
|
Str VM::disassemble(CodeObject_ co){
|
||||||
@ -742,14 +747,10 @@ Str VM::disassemble(CodeObject_ co){
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<int> jumpTargets;
|
std::vector<int> jumpTargets;
|
||||||
for(auto byte : co->codes){
|
for(int i=0; i<co->codes.size(); i++){
|
||||||
if(byte.op == OP_JUMP_ABSOLUTE || byte.op == OP_POP_JUMP_IF_FALSE || byte.op == OP_SHORTCUT_IF_FALSE_OR_POP || byte.op == OP_LOOP_CONTINUE){
|
Bytecode byte = co->codes[i];
|
||||||
jumpTargets.push_back(byte.arg);
|
if(byte.is_forward_jump()){
|
||||||
}
|
jumpTargets.push_back((int16_t)byte.arg + i);
|
||||||
if(byte.op == OP_GOTO){
|
|
||||||
// TODO: pre-compute jump targets for OP_GOTO
|
|
||||||
int* target = co->labels.try_get_2_likely_found(StrName(byte.arg));
|
|
||||||
if(target != nullptr) jumpTargets.push_back(*target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SStream ss;
|
SStream ss;
|
||||||
@ -773,11 +774,8 @@ Str VM::disassemble(CodeObject_ co){
|
|||||||
std::string bc_name(OP_NAMES[byte.op]);
|
std::string bc_name(OP_NAMES[byte.op]);
|
||||||
if(co->lines[i].is_virtual) bc_name += '*';
|
if(co->lines[i].is_virtual) bc_name += '*';
|
||||||
ss << " " << pad(bc_name, 25) << " ";
|
ss << " " << pad(bc_name, 25) << " ";
|
||||||
// ss << pad(byte.arg == -1 ? "" : std::to_string(byte.arg), 5);
|
std::string argStr = _opcode_argstr(this, i, byte, co.get());
|
||||||
std::string argStr = _opcode_argstr(this, byte, co.get());
|
|
||||||
ss << argStr;
|
ss << argStr;
|
||||||
// ss << pad(argStr, 40); // may overflow
|
|
||||||
// ss << co->blocks[byte.block].type;
|
|
||||||
if(i != co->codes.size() - 1) ss << '\n';
|
if(i != co->codes.size() - 1) ss << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,7 +833,7 @@ void VM::__log_s_data(const char* title) {
|
|||||||
output.pop_back(); output.pop_back();
|
output.pop_back(); output.pop_back();
|
||||||
}
|
}
|
||||||
output.push_back(']');
|
output.push_back(']');
|
||||||
Bytecode byte = frame->co->codes[frame->_ip];
|
Bytecode byte = *frame->_ip;
|
||||||
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
|
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user