mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-22 20:40:18 +00:00
up
This commit is contained in:
parent
2d8db01cf1
commit
684ebe8e79
68
src/ceval.h
68
src/ceval.h
@ -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
|
||||
/**********************************************************************/
|
||||
|
@ -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;
|
||||
|
||||
|
@ -49,6 +49,12 @@
|
||||
#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__)
|
||||
typedef int32_t i64;
|
||||
typedef float f64;
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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();
|
||||
|
37
src/frame.h
37
src/frame.h
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user