mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-23 04:50:17 +00:00
up
This commit is contained in:
parent
2d8db01cf1
commit
684ebe8e79
76
src/ceval.h
76
src/ceval.h
@ -18,42 +18,37 @@ inline PyObject* VM::_run_top_frame(){
|
|||||||
try{
|
try{
|
||||||
if(need_raise){ need_raise = false; _raise(); }
|
if(need_raise){ need_raise = false; _raise(); }
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
#define USE_COMPUTED_GOTO 0
|
|
||||||
|
|
||||||
#if USE_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];}
|
|
||||||
#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: \
|
|
||||||
CASE_OP_##op:
|
|
||||||
|
|
||||||
{
|
|
||||||
Bytecode byte = frame->next_bytecode();
|
|
||||||
#if !USE_COMPUTED_GOTO
|
|
||||||
__NEXT_STEP:;
|
|
||||||
#endif
|
|
||||||
/* NOTE:
|
/* NOTE:
|
||||||
* Be aware of accidental gc!
|
* Be aware of accidental gc!
|
||||||
* DO NOT leave any strong reference of PyObject* in the C stack
|
* DO NOT leave any strong reference of PyObject* in the C stack
|
||||||
* For example, frame->popx() returns a strong reference which may be dangerous
|
* 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`
|
* `Args` containing strong references is safe if it is passed to `call` or `fast_call`
|
||||||
*/
|
*/
|
||||||
|
{
|
||||||
|
Bytecode byte = frame->next_bytecode();
|
||||||
|
|
||||||
|
#if PK_ENABLE_COMPUTED_GOTO
|
||||||
|
static void* OP_LABELS[] = {
|
||||||
|
#define OPCODE(name) &&CASE_OP_##name,
|
||||||
|
#include "opcodes.h"
|
||||||
|
#undef OPCODE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DISPATCH() { byte = frame->next_bytecode(); goto *OP_LABELS[byte.op];}
|
||||||
|
#define TARGET(op) CASE_OP_##op:
|
||||||
|
goto *OP_LABELS[byte.op];
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define TARGET(op) case OP_##op:
|
||||||
|
#define DISPATCH() { byte = frame->next_bytecode(); goto __NEXT_STEP;}
|
||||||
|
|
||||||
|
__NEXT_STEP:;
|
||||||
#if DEBUG_CEVAL_STEP
|
#if DEBUG_CEVAL_STEP
|
||||||
std::cout << frame->stack_info() << " " << OP_NAMES[byte.op] << std::endl;
|
std::cout << frame->stack_info() << " " << OP_NAMES[byte.op] << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (byte.op)
|
switch (byte.op)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
TARGET(NO_OP) DISPATCH();
|
TARGET(NO_OP) DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(POP_TOP) frame->pop(); DISPATCH();
|
TARGET(POP_TOP) frame->pop(); DISPATCH();
|
||||||
@ -65,7 +60,10 @@ __NEXT_STEP:;
|
|||||||
frame->pop();
|
frame->pop();
|
||||||
} DISPATCH();
|
} 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_NONE) frame->push(None); DISPATCH();
|
||||||
TARGET(LOAD_TRUE) frame->push(True); DISPATCH();
|
TARGET(LOAD_TRUE) frame->push(True); DISPATCH();
|
||||||
TARGET(LOAD_FALSE) frame->push(False); DISPATCH();
|
TARGET(LOAD_FALSE) frame->push(False); DISPATCH();
|
||||||
@ -79,6 +77,7 @@ __NEXT_STEP:;
|
|||||||
TARGET(LOAD_NULL) frame->push(_py_null); DISPATCH();
|
TARGET(LOAD_NULL) frame->push(_py_null); DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(LOAD_NAME) {
|
TARGET(LOAD_NAME) {
|
||||||
|
heap._auto_collect();
|
||||||
StrName name = frame->co->names[byte.arg];
|
StrName name = frame->co->names[byte.arg];
|
||||||
PyObject* val;
|
PyObject* val;
|
||||||
val = frame->f_locals().try_get(name);
|
val = frame->f_locals().try_get(name);
|
||||||
@ -92,6 +91,7 @@ __NEXT_STEP:;
|
|||||||
vm->NameError(name);
|
vm->NameError(name);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(LOAD_GLOBAL) {
|
TARGET(LOAD_GLOBAL) {
|
||||||
|
heap._auto_collect();
|
||||||
StrName name = frame->co->names[byte.arg];
|
StrName name = frame->co->names[byte.arg];
|
||||||
PyObject* val = frame->f_globals().try_get(name);
|
PyObject* val = frame->f_globals().try_get(name);
|
||||||
if(val != nullptr) { frame->push(val); DISPATCH(); }
|
if(val != nullptr) { frame->push(val); DISPATCH(); }
|
||||||
@ -239,22 +239,22 @@ __NEXT_STEP:;
|
|||||||
DISPATCH()
|
DISPATCH()
|
||||||
TARGET(COMPARE_LT)
|
TARGET(COMPARE_LT)
|
||||||
INT_BINARY_OP(<, __lt__)
|
INT_BINARY_OP(<, __lt__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(COMPARE_LE)
|
TARGET(COMPARE_LE)
|
||||||
INT_BINARY_OP(<=, __le__)
|
INT_BINARY_OP(<=, __le__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(COMPARE_EQ)
|
TARGET(COMPARE_EQ)
|
||||||
INT_BINARY_OP(==, __eq__)
|
INT_BINARY_OP(==, __eq__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(COMPARE_NE)
|
TARGET(COMPARE_NE)
|
||||||
INT_BINARY_OP(!=, __ne__)
|
INT_BINARY_OP(!=, __ne__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(COMPARE_GT)
|
TARGET(COMPARE_GT)
|
||||||
INT_BINARY_OP(>, __gt__)
|
INT_BINARY_OP(>, __gt__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(COMPARE_GE)
|
TARGET(COMPARE_GE)
|
||||||
INT_BINARY_OP(>=, __ge__)
|
INT_BINARY_OP(>=, __ge__)
|
||||||
PREDICTED_DISPATCH(POP_JUMP_IF_FALSE)
|
DISPATCH()
|
||||||
TARGET(BITWISE_LSHIFT)
|
TARGET(BITWISE_LSHIFT)
|
||||||
INT_BINARY_OP(<<, __lshift__)
|
INT_BINARY_OP(<<, __lshift__)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -469,9 +469,6 @@ __NEXT_STEP:;
|
|||||||
// TARGET(WITH_ENTER) call(frame->pop_value(this), __enter__, no_arg()); DISPATCH();
|
// 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(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) {
|
TARGET(ASSERT) {
|
||||||
PyObject* obj = frame->top();
|
PyObject* obj = frame->top();
|
||||||
Str msg;
|
Str msg;
|
||||||
@ -497,10 +494,17 @@ __NEXT_STEP:;
|
|||||||
_error(type, msg);
|
_error(type, msg);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(RE_RAISE) _raise(); 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"));
|
default: throw std::runtime_error(fmt(OP_NAMES[byte.op], " is not implemented"));
|
||||||
|
#else
|
||||||
|
default: __builtin_unreachable();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef DISPATCH
|
#undef DISPATCH
|
||||||
#undef TARGET
|
#undef TARGET
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
@ -39,8 +39,12 @@ enum CodeBlockType {
|
|||||||
struct CodeBlock {
|
struct CodeBlock {
|
||||||
CodeBlockType type;
|
CodeBlockType type;
|
||||||
int parent; // parent index in blocks
|
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 start; // start index of this block in codes, inclusive
|
||||||
int end; // end index of this block in codes, exclusive
|
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 {
|
struct CodeObject {
|
||||||
@ -58,7 +62,7 @@ struct CodeObject {
|
|||||||
List consts;
|
List consts;
|
||||||
std::vector<StrName> names;
|
std::vector<StrName> names;
|
||||||
std::set<Str> global_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::map<StrName, int> labels;
|
||||||
std::vector<FuncDecl_> func_decls;
|
std::vector<FuncDecl_> func_decls;
|
||||||
|
|
||||||
|
@ -49,6 +49,12 @@
|
|||||||
#define PK_ENABLE_FILEIO 0 // TODO: refactor this
|
#define PK_ENABLE_FILEIO 0 // TODO: refactor this
|
||||||
#endif
|
#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__)
|
#if defined(__EMSCRIPTEN__) || defined(__arm__) || defined(__i386__)
|
||||||
typedef int32_t i64;
|
typedef int32_t i64;
|
||||||
typedef float f64;
|
typedef float f64;
|
||||||
|
@ -607,9 +607,7 @@ __SUBSCR_END:
|
|||||||
|
|
||||||
void compile_try_except() {
|
void compile_try_except() {
|
||||||
ctx()->enter_block(TRY_EXCEPT);
|
ctx()->enter_block(TRY_EXCEPT);
|
||||||
ctx()->emit(OP_TRY_BLOCK_ENTER, BC_NOARG, prev().line);
|
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->emit(OP_TRY_BLOCK_EXIT, BC_NOARG, BC_KEEPLINE);
|
|
||||||
std::vector<int> patches = {
|
std::vector<int> patches = {
|
||||||
ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
|
ctx()->emit(OP_JUMP_ABSOLUTE, BC_NOARG, BC_KEEPLINE)
|
||||||
};
|
};
|
||||||
|
@ -37,19 +37,22 @@ struct CodeEmitContext{
|
|||||||
|
|
||||||
int curr_block_i = 0;
|
int curr_block_i = 0;
|
||||||
bool is_compiling_class = false;
|
bool is_compiling_class = false;
|
||||||
|
int for_loop_depth = 0;
|
||||||
|
|
||||||
bool is_curr_block_loop() const {
|
bool is_curr_block_loop() const {
|
||||||
return co->blocks[curr_block_i].type == FOR_LOOP || co->blocks[curr_block_i].type == WHILE_LOOP;
|
return co->blocks[curr_block_i].type == FOR_LOOP || co->blocks[curr_block_i].type == WHILE_LOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void enter_block(CodeBlockType type){
|
void enter_block(CodeBlockType type){
|
||||||
co->blocks.push_back(CodeBlock{
|
if(type == FOR_LOOP) for_loop_depth++;
|
||||||
type, curr_block_i, (int)co->codes.size()
|
co->blocks.push_back(CodeBlock(
|
||||||
});
|
type, curr_block_i, for_loop_depth, (int)co->codes.size()
|
||||||
|
));
|
||||||
curr_block_i = co->blocks.size()-1;
|
curr_block_i = co->blocks.size()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit_block(){
|
void exit_block(){
|
||||||
|
if(co->blocks[curr_block_i].type == FOR_LOOP) for_loop_depth--;
|
||||||
co->blocks[curr_block_i].end = co->codes.size();
|
co->blocks[curr_block_i].end = co->codes.size();
|
||||||
curr_block_i = co->blocks[curr_block_i].parent;
|
curr_block_i = co->blocks[curr_block_i].parent;
|
||||||
if(curr_block_i < 0) UNREACHABLE();
|
if(curr_block_i < 0) UNREACHABLE();
|
||||||
|
37
src/frame.h
37
src/frame.h
@ -17,7 +17,6 @@ struct Frame {
|
|||||||
PyObject* _module;
|
PyObject* _module;
|
||||||
NameDict_ _locals;
|
NameDict_ _locals;
|
||||||
NameDict_ _closure;
|
NameDict_ _closure;
|
||||||
std::vector<std::pair<int, ValueStack>> s_try_block;
|
|
||||||
|
|
||||||
NameDict& f_locals() noexcept { return _locals!=nullptr ? *_locals : _module->attr(); }
|
NameDict& f_locals() noexcept { return _locals!=nullptr ? *_locals : _module->attr(); }
|
||||||
NameDict& f_globals() noexcept { return _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_abs(int i){ _next_ip = i; }
|
||||||
void jump_rel(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(){
|
bool jump_to_exception_handler(){
|
||||||
if(s_try_block.empty()) return false;
|
// try to find a parent try block
|
||||||
PyObject* obj = popx();
|
int block = co->codes[_ip].block;
|
||||||
auto& p = s_try_block.back();
|
while(block >= 0){
|
||||||
_data = std::move(p.second);
|
if(co->blocks[block].type == TRY_EXCEPT) break;
|
||||||
_data.push_back(obj);
|
block = co->blocks[block].parent;
|
||||||
_next_ip = co->blocks[p.first].end;
|
}
|
||||||
on_try_block_exit();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _exit_block(int i){
|
int _exit_block(int i){
|
||||||
if(co->blocks[i].type == FOR_LOOP) pop();
|
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;
|
return co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,15 +151,12 @@ struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark() const {
|
void _gc_mark() const {
|
||||||
// this frame has been moved
|
// do return if this frame has been moved
|
||||||
if(_data._data == nullptr) return;
|
if(_data._data == nullptr) return;
|
||||||
for(PyObject* obj : _data) OBJ_MARK(obj);
|
for(PyObject* obj : _data) OBJ_MARK(obj);
|
||||||
OBJ_MARK(_module);
|
OBJ_MARK(_module);
|
||||||
if(_locals != nullptr) _locals->_gc_mark();
|
if(_locals != nullptr) _locals->_gc_mark();
|
||||||
if(_closure != nullptr) _closure->_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();
|
co->_gc_mark();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -102,8 +102,6 @@ OPCODE(STORE_CLASS_ATTR)
|
|||||||
// OPCODE(WITH_ENTER)
|
// OPCODE(WITH_ENTER)
|
||||||
// OPCODE(WITH_EXIT)
|
// OPCODE(WITH_EXIT)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(TRY_BLOCK_ENTER)
|
|
||||||
OPCODE(TRY_BLOCK_EXIT)
|
|
||||||
OPCODE(ASSERT)
|
OPCODE(ASSERT)
|
||||||
OPCODE(EXCEPTION_MATCH)
|
OPCODE(EXCEPTION_MATCH)
|
||||||
OPCODE(RAISE)
|
OPCODE(RAISE)
|
||||||
|
@ -105,6 +105,11 @@ struct pod_vector{
|
|||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resize(int size){
|
||||||
|
if(size > _capacity) reserve(size);
|
||||||
|
_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
~pod_vector() {
|
~pod_vector() {
|
||||||
if(_data!=nullptr) pool128.dealloc(_data);
|
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:
|
class A:
|
||||||
def __getitem__(self, i):
|
def __getitem__(self, i):
|
||||||
raise KeyError(i)
|
raise KeyError(i)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user