This commit is contained in:
blueloveTH 2023-04-10 12:58:32 +08:00
parent 2d8db01cf1
commit 684ebe8e79
9 changed files with 94 additions and 63 deletions

View File

@ -18,42 +18,37 @@ inline PyObject* VM::_run_top_frame(){
try{
if(need_raise){ need_raise = false; _raise(); }
/**********************************************************************/
#define USE_COMPUTED_GOTO 0
/* NOTE:
* Be aware of accidental gc!
* DO NOT leave any strong reference of PyObject* in the C stack
* For example, frame->popx() returns a strong reference which may be dangerous
* `Args` containing strong references is safe if it is passed to `call` or `fast_call`
*/
{
Bytecode byte = frame->next_bytecode();
#if USE_COMPUTED_GOTO
#if PK_ENABLE_COMPUTED_GOTO
static void* OP_LABELS[] = {
#define OPCODE(name) &&CASE_OP_##name,
#include "opcodes.h"
#undef OPCODE
};
#define DISPATCH() {heap._auto_collect(); byte = frame->next_bytecode(); goto *OP_LABELS[byte.op];}
#define PREDICTED_DISPATCH(x) {heap._auto_collect(); byte = frame->next_bytecode(); if(byte.op == OP_##x) goto CASE_OP_##x; goto *OP_LABELS[byte.op];}
#define DISPATCH() { byte = frame->next_bytecode(); goto *OP_LABELS[byte.op];}
#define TARGET(op) CASE_OP_##op:
goto *OP_LABELS[byte.op];
#else
#define DISPATCH() {heap._auto_collect(); byte = frame->next_bytecode(); goto __NEXT_STEP;}
#define PREDICTED_DISPATCH(x) {heap._auto_collect(); byte = frame->next_bytecode(); if(byte.op == OP_##x) goto CASE_OP_##x; goto __NEXT_STEP;}
#endif
#define TARGET(op) case OP_##op:
#define DISPATCH() { byte = frame->next_bytecode(); goto __NEXT_STEP;}
#define TARGET(op) case OP_##op: \
CASE_OP_##op:
{
Bytecode byte = frame->next_bytecode();
#if !USE_COMPUTED_GOTO
__NEXT_STEP:;
#endif
/* NOTE:
* Be aware of accidental gc!
* DO NOT leave any strong reference of PyObject* in the C stack
* For example, frame->popx() returns a strong reference which may be dangerous
* `Args` containing strong references is safe if it is passed to `call` or `fast_call`
*/
#if DEBUG_CEVAL_STEP
std::cout << frame->stack_info() << " " << OP_NAMES[byte.op] << std::endl;
#endif
switch (byte.op)
{
#endif
TARGET(NO_OP) DISPATCH();
/*****************************************/
TARGET(POP_TOP) frame->pop(); DISPATCH();
@ -65,7 +60,10 @@ __NEXT_STEP:;
frame->pop();
} DISPATCH();
/*****************************************/
TARGET(LOAD_CONST) frame->push(frame->co->consts[byte.arg]); DISPATCH();
TARGET(LOAD_CONST)
heap._auto_collect();
frame->push(frame->co->consts[byte.arg]);
DISPATCH();
TARGET(LOAD_NONE) frame->push(None); DISPATCH();
TARGET(LOAD_TRUE) frame->push(True); DISPATCH();
TARGET(LOAD_FALSE) frame->push(False); DISPATCH();
@ -79,6 +77,7 @@ __NEXT_STEP:;
TARGET(LOAD_NULL) frame->push(_py_null); DISPATCH();
/*****************************************/
TARGET(LOAD_NAME) {
heap._auto_collect();
StrName name = frame->co->names[byte.arg];
PyObject* val;
val = frame->f_locals().try_get(name);
@ -92,6 +91,7 @@ __NEXT_STEP:;
vm->NameError(name);
} DISPATCH();
TARGET(LOAD_GLOBAL) {
heap._auto_collect();
StrName name = frame->co->names[byte.arg];
PyObject* val = frame->f_globals().try_get(name);
if(val != nullptr) { frame->push(val); DISPATCH(); }
@ -239,22 +239,22 @@ __NEXT_STEP:;
DISPATCH()
TARGET(COMPARE_LT)
INT_BINARY_OP(<, __lt__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(COMPARE_LE)
INT_BINARY_OP(<=, __le__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(COMPARE_EQ)
INT_BINARY_OP(==, __eq__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(COMPARE_NE)
INT_BINARY_OP(!=, __ne__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(COMPARE_GT)
INT_BINARY_OP(>, __gt__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(COMPARE_GE)
INT_BINARY_OP(>=, __ge__)
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
DISPATCH()
TARGET(BITWISE_LSHIFT)
INT_BINARY_OP(<<, __lshift__)
DISPATCH()
@ -469,9 +469,6 @@ __NEXT_STEP:;
// TARGET(WITH_ENTER) call(frame->pop_value(this), __enter__, no_arg()); DISPATCH();
// TARGET(WITH_EXIT) call(frame->pop_value(this), __exit__, no_arg()); DISPATCH();
/*****************************************/
TARGET(TRY_BLOCK_ENTER) frame->on_try_block_enter(); DISPATCH();
TARGET(TRY_BLOCK_EXIT) frame->on_try_block_exit(); DISPATCH();
/*****************************************/
TARGET(ASSERT) {
PyObject* obj = frame->top();
Str msg;
@ -497,10 +494,17 @@ __NEXT_STEP:;
_error(type, msg);
} DISPATCH();
TARGET(RE_RAISE) _raise(); DISPATCH();
#if !PK_ENABLE_COMPUTED_GOTO
#if DEBUG_EXTRA_CHECK
default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented"));
#else
default: __builtin_unreachable();
#endif
}
UNREACHABLE();
#endif
}
#undef DISPATCH
#undef TARGET
/**********************************************************************/

View File

@ -39,8 +39,12 @@ enum CodeBlockType {
struct CodeBlock {
CodeBlockType type;
int parent; // parent index in blocks
int for_loop_depth; // this is used for exception handling
int start; // start index of this block in codes, inclusive
int end; // end index of this block in codes, exclusive
CodeBlock(CodeBlockType type, int parent, int for_loop_depth, int start):
type(type), parent(parent), for_loop_depth(for_loop_depth), start(start), end(-1) {}
};
struct CodeObject {
@ -58,7 +62,7 @@ struct CodeObject {
List consts;
std::vector<StrName> names;
std::set<Str> global_names;
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
std::vector<CodeBlock> blocks = { CodeBlock(NO_BLOCK, -1, 0, 0) };
std::map<StrName, int> labels;
std::vector<FuncDecl_> func_decls;

View File

@ -44,9 +44,15 @@
#define DEBUG_GC_STATS 0
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
#define PK_ENABLE_FILEIO 0
#define PK_ENABLE_FILEIO 0
#else
#define PK_ENABLE_FILEIO 0 // TODO: refactor this
#define PK_ENABLE_FILEIO 0 // TODO: refactor this
#endif
#if _MSC_VER
#define PK_ENABLE_COMPUTED_GOTO 0
#else
#define PK_ENABLE_COMPUTED_GOTO 1
#endif
#if defined(__EMSCRIPTEN__) || defined(__arm__) || defined(__i386__)

View File

@ -607,9 +607,7 @@ __SUBSCR_END:
void compile_try_except() {
ctx()->enter_block(TRY_EXCEPT);
ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line);
compile_block_body();
ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE);
std::vector<int> patches = {
ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
};

View File

@ -37,19 +37,22 @@ struct CodeEmitContext{
int curr_block_i = 0;
bool is_compiling_class = false;
int for_loop_depth = 0;
bool is_curr_block_loop() const {
return co->blocks[curr_block_i].type == FOR_LOOP || co->blocks[curr_block_i].type == WHILE_LOOP;
}
void enter_block(CodeBlockType type){
co->blocks.push_back(CodeBlock{
type, curr_block_i, (int)co->codes.size()
});
if(type == FOR_LOOP) for_loop_depth++;
co->blocks.push_back(CodeBlock(
type, curr_block_i, for_loop_depth, (int)co->codes.size()
));
curr_block_i = co->blocks.size()-1;
}
void exit_block(){
if(co->blocks[curr_block_i].type == FOR_LOOP) for_loop_depth--;
co->blocks[curr_block_i].end = co->codes.size();
curr_block_i = co->blocks[curr_block_i].parent;
if(curr_block_i < 0) UNREACHABLE();

View File

@ -17,7 +17,6 @@ struct Frame {
PyObject* _module;
NameDict_ _locals;
NameDict_ _closure;
std::vector<std::pair<int, ValueStack>> s_try_block;
NameDict& f_locals() noexcept { return _locals!=nullptr ? *_locals : _module->attr(); }
NameDict& f_globals() noexcept { return _module->attr(); }
@ -104,28 +103,27 @@ struct Frame {
void jump_abs(int i){ _next_ip = i; }
void jump_rel(int i){ _next_ip += i; }
void on_try_block_enter(){
s_try_block.emplace_back(co->codes[_ip].block, _data);
}
void on_try_block_exit(){
s_try_block.pop_back();
}
bool jump_to_exception_handler(){
if(s_try_block.empty()) return false;
PyObject* obj = popx();
auto& p = s_try_block.back();
_data = std::move(p.second);
_data.push_back(obj);
_next_ip = co->blocks[p.first].end;
on_try_block_exit();
// try to find a parent try block
int block = co->codes[_ip].block;
while(block >= 0){
if(co->blocks[block].type == TRY_EXCEPT) break;
block = co->blocks[block].parent;
}
if(block < 0) return false;
PyObject* obj = popx(); // pop exception object
// get the stack size of the try block (depth of for loops)
int stack_size = co->blocks[block].for_loop_depth;
// std::cout << "stack_size: " << stack_size << std::endl;
if(_data.size() < stack_size) throw std::runtime_error("invalid stack size");
_data.resize(stack_size); // rollback the stack
_data.push_back(obj); // push exception object
_next_ip = co->blocks[block].end;
return true;
}
int _exit_block(int i){
if(co->blocks[i].type == FOR_LOOP) pop();
else if(co->blocks[i].type == TRY_EXCEPT) on_try_block_exit();
return co->blocks[i].parent;
}
@ -153,15 +151,12 @@ struct Frame {
}
void _gc_mark() const {
// this frame has been moved
// do return if this frame has been moved
if(_data._data == nullptr) return;
for(PyObject* obj : _data) OBJ_MARK(obj);
OBJ_MARK(_module);
if(_locals != nullptr) _locals->_gc_mark();
if(_closure != nullptr) _closure->_gc_mark();
for(auto& p : s_try_block){
for(PyObject* obj : p.second) OBJ_MARK(obj);
}
co->_gc_mark();
}
};

View File

@ -102,8 +102,6 @@ OPCODE(STORE_CLASS_ATTR)
// OPCODE(WITH_ENTER)
// OPCODE(WITH_EXIT)
/**************************/
OPCODE(TRY_BLOCK_ENTER)
OPCODE(TRY_BLOCK_EXIT)
OPCODE(ASSERT)
OPCODE(EXCEPTION_MATCH)
OPCODE(RAISE)

View File

@ -105,6 +105,11 @@ struct pod_vector{
_size--;
}
void resize(int size){
if(size > _capacity) reserve(size);
_size = size;
}
~pod_vector() {
if(_data!=nullptr) pool128.dealloc(_data);
}

View File

@ -1,3 +1,21 @@
try:
for i in range(5):
raise KeyError(i)
exit(1)
except KeyError:
pass
x = 0
for i in range(5):
try:
for j in range(5):
while True:
raise KeyError(i)
x += 3
except KeyError:
x += i
assert x == 10
class A:
def __getitem__(self, i):
raise KeyError(i)