mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-24 13:30:18 +00:00
* init * some optimize * Update frame.h * remove `LOAD_INTEGER` * Update vm.cpp * some optimize * some fix * Revert "remove `LOAD_INTEGER`" This reverts commit c0b965aee2f64fbfae0b20f41d714688649d20cf. * some fix * Update expr.cpp * some fix * Update retype.yml
This commit is contained in:
parent
9bfe8c1bad
commit
65440c2034
@ -49,7 +49,7 @@ Some variables can be set to control the build process:
|
|||||||
+ `PK_BUILD_SHARED_LIB` - Build the shared (for C-APIs only)
|
+ `PK_BUILD_SHARED_LIB` - Build the shared (for C-APIs only)
|
||||||
+ `PK_ENABLE_OS` - Enable OS related features (default mode is sandboxed)
|
+ `PK_ENABLE_OS` - Enable OS related features (default mode is sandboxed)
|
||||||
|
|
||||||
It is safe to use `main` branch in production.
|
It is safe to use `main` branch in production if CI is green.
|
||||||
|
|
||||||
### Compile Flags
|
### Compile Flags
|
||||||
|
|
||||||
@ -197,10 +197,6 @@ Your sponsorship will help us develop pkpy continuously.
|
|||||||
|
|
||||||
An excellent learning material. It illustrates how Python's virtual machine works.
|
An excellent learning material. It illustrates how Python's virtual machine works.
|
||||||
|
|
||||||
+ [box2d](https://box2d.org/)
|
|
||||||
|
|
||||||
The world's best 2D physics engine, written by Erin Catto. `box2d` now becomes a built-in module in pkpy `v1.1.3` and later.
|
|
||||||
|
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ output: .retype
|
|||||||
url: https://pocketpy.dev
|
url: https://pocketpy.dev
|
||||||
branding:
|
branding:
|
||||||
title: pocketpy
|
title: pocketpy
|
||||||
label: v1.4.1
|
label: v1.4.3
|
||||||
logo: "./static/logo.png"
|
logo: "./static/logo.png"
|
||||||
favicon: "./static/logo.png"
|
favicon: "./static/logo.png"
|
||||||
meta:
|
meta:
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
#define PK_VERSION "1.4.2"
|
#define PK_VERSION "1.4.3"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
|||||||
@ -105,6 +105,7 @@ struct CodeEmitContext{
|
|||||||
void exit_block();
|
void exit_block();
|
||||||
void emit_expr(); // clear the expression stack and generate bytecode
|
void emit_expr(); // clear the expression stack and generate bytecode
|
||||||
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual=false);
|
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual=false);
|
||||||
|
int emit_int(i64 value, int line);
|
||||||
void patch_jump(int index);
|
void patch_jump(int index);
|
||||||
bool add_label(StrName name);
|
bool add_label(StrName name);
|
||||||
int add_varname(StrName name);
|
int add_varname(StrName name);
|
||||||
|
|||||||
@ -84,18 +84,21 @@ struct Frame {
|
|||||||
|
|
||||||
const CodeObject* co;
|
const CodeObject* co;
|
||||||
PyObject* _module;
|
PyObject* _module;
|
||||||
PyObject* _callable; // weak ref
|
PyObject* _callable; // a function object or nullptr (global scope)
|
||||||
FastLocals _locals;
|
FastLocals _locals;
|
||||||
|
|
||||||
NameDict& f_globals() noexcept { return _module->attr(); }
|
NameDict& f_globals() noexcept { return _module->attr(); }
|
||||||
PyObject* f_closure_try_get(StrName name);
|
PyObject* f_closure_try_get(StrName name);
|
||||||
|
|
||||||
Frame(PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable)
|
// function scope
|
||||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, p0) { }
|
Frame(PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyObject** _locals_base)
|
||||||
|
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base) { }
|
||||||
|
|
||||||
|
// exec/eval
|
||||||
Frame(PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals)
|
Frame(PyObject** p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals)
|
||||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
|
: _ip(-1), _next_ip(0), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals) { }
|
||||||
|
|
||||||
|
// global scope
|
||||||
Frame(PyObject** p0, const CodeObject_& co, PyObject* _module)
|
Frame(PyObject** p0, const CodeObject_& co, PyObject* _module)
|
||||||
: _ip(-1), _next_ip(0), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
|
: _ip(-1), _next_ip(0), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0) {}
|
||||||
|
|
||||||
@ -125,14 +128,46 @@ struct Frame {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using CallstackContainer = small_vector_no_copy_and_move<Frame, 16>;
|
struct LinkedFrame{
|
||||||
|
LinkedFrame* f_back;
|
||||||
|
Frame frame;
|
||||||
|
template<typename... Args>
|
||||||
|
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct FrameId{
|
struct CallStack{
|
||||||
CallstackContainer* data;
|
static_assert(sizeof(LinkedFrame) <= 64 && std::is_trivially_destructible_v<LinkedFrame>);
|
||||||
int index;
|
|
||||||
FrameId(CallstackContainer* data, int index) : data(data), index(index) {}
|
LinkedFrame* _tail;
|
||||||
Frame* operator->() const { return &data->operator[](index); }
|
int _size;
|
||||||
Frame* get() const { return &data->operator[](index); }
|
CallStack(): _tail(nullptr), _size(0) {}
|
||||||
|
|
||||||
|
int size() const { return _size; }
|
||||||
|
bool empty() const { return _size == 0; }
|
||||||
|
void clear(){ while(!empty()) pop(); }
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void emplace(Args&&... args){
|
||||||
|
_tail = new(pool64_alloc<LinkedFrame>()) LinkedFrame(_tail, std::forward<Args>(args)...);
|
||||||
|
++_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop(){
|
||||||
|
#if PK_DEBUG_EXTRA_CHECK
|
||||||
|
if(empty()) PK_FATAL_ERROR();
|
||||||
|
#endif
|
||||||
|
LinkedFrame* p = _tail;
|
||||||
|
_tail = p->f_back;
|
||||||
|
pool64_dealloc(p);
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame& top() const { return _tail->frame; }
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
void apply(Func&& f){
|
||||||
|
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace pkpy
|
}; // namespace pkpy
|
||||||
@ -14,7 +14,7 @@ struct _LineRecord{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct _FrameRecord{
|
struct _FrameRecord{
|
||||||
FrameId frame;
|
LinkedFrame* frame;
|
||||||
clock_t prev_time;
|
clock_t prev_time;
|
||||||
_LineRecord* prev_record;
|
_LineRecord* prev_record;
|
||||||
};
|
};
|
||||||
@ -26,8 +26,8 @@ struct LineProfiler{
|
|||||||
std::set<FuncDecl*> functions;
|
std::set<FuncDecl*> functions;
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
void _step(FrameId frame);
|
void _step(LinkedFrame*);
|
||||||
void _step_end(FrameId frame, int line);
|
void _step_end(LinkedFrame*, int);
|
||||||
void end();
|
void end();
|
||||||
Str stats();
|
Str stats();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -94,7 +94,7 @@ class VM {
|
|||||||
public:
|
public:
|
||||||
ManagedHeap heap;
|
ManagedHeap heap;
|
||||||
ValueStack s_data;
|
ValueStack s_data;
|
||||||
stack_no_copy<Frame, CallstackContainer> callstack;
|
CallStack callstack;
|
||||||
std::vector<PyTypeInfo> _all_types;
|
std::vector<PyTypeInfo> _all_types;
|
||||||
|
|
||||||
NameDict _modules; // loaded modules
|
NameDict _modules; // loaded modules
|
||||||
@ -151,7 +151,7 @@ public:
|
|||||||
|
|
||||||
VM(bool enable_os=true);
|
VM(bool enable_os=true);
|
||||||
|
|
||||||
FrameId top_frame();
|
Frame* top_frame();
|
||||||
void _pop_frame();
|
void _pop_frame();
|
||||||
|
|
||||||
PyObject* py_str(PyObject* obj);
|
PyObject* py_str(PyObject* obj);
|
||||||
@ -364,9 +364,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type _tp(PyObject* obj){
|
Type _tp(PyObject* obj){
|
||||||
|
if(!is_tagged(obj)) return obj->type;
|
||||||
if(is_int(obj)) return tp_int;
|
if(is_int(obj)) return tp_int;
|
||||||
if(is_float(obj)) return tp_float;
|
return tp_float;
|
||||||
return obj->type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* _t(PyObject* obj){
|
PyObject* _t(PyObject* obj){
|
||||||
|
|||||||
@ -44,19 +44,12 @@ bool VM::py_ge(PyObject* _0, PyObject* _1){
|
|||||||
|
|
||||||
#undef BINARY_F_COMPARE
|
#undef BINARY_F_COMPARE
|
||||||
|
|
||||||
// static i64 _py_sint(PyObject* obj) noexcept {
|
|
||||||
// return (i64)(PK_BITS(obj) >> 2);
|
|
||||||
// }
|
|
||||||
|
|
||||||
PyObject* VM::_run_top_frame(){
|
PyObject* VM::_run_top_frame(){
|
||||||
FrameId frame = top_frame();
|
Frame* frame = top_frame();
|
||||||
const int base_id = frame.index;
|
const Frame* base_frame = frame;
|
||||||
bool need_raise = false;
|
bool need_raise = false;
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
#if PK_DEBUG_EXTRA_CHECK
|
|
||||||
if(frame.index < base_id) PK_FATAL_ERROR();
|
|
||||||
#endif
|
|
||||||
try{
|
try{
|
||||||
if(need_raise){ need_raise = false; _raise(); }
|
if(need_raise){ need_raise = false; _raise(); }
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
@ -67,14 +60,14 @@ PyObject* VM::_run_top_frame(){
|
|||||||
{
|
{
|
||||||
|
|
||||||
#define CEVAL_STEP_CALLBACK() \
|
#define CEVAL_STEP_CALLBACK() \
|
||||||
if(_ceval_on_step) _ceval_on_step(this, frame.get(), byte); \
|
if(_ceval_on_step) _ceval_on_step(this, frame, byte); \
|
||||||
if(_profiler) _profiler->_step(frame);
|
if(_profiler) _profiler->_step(callstack._tail);
|
||||||
|
|
||||||
#define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; }
|
#define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; }
|
||||||
__NEXT_FRAME:
|
__NEXT_FRAME:
|
||||||
// cache
|
// cache
|
||||||
const CodeObject* co = frame->co;
|
const CodeObject* co = frame->co;
|
||||||
const auto& co_consts = co->consts;
|
PyObject** co_consts = const_cast<PyObject**>(co->consts.data());
|
||||||
const Bytecode* co_codes = co->codes.data();
|
const Bytecode* co_codes = co->codes.data();
|
||||||
|
|
||||||
Bytecode byte = co_codes[frame->next_bytecode()];
|
Bytecode byte = co_codes[frame->next_bytecode()];
|
||||||
@ -598,7 +591,7 @@ __NEXT_STEP:;
|
|||||||
TARGET(RETURN_VALUE){
|
TARGET(RETURN_VALUE){
|
||||||
PyObject* _0 = byte.arg == BC_NOARG ? POPX() : None;
|
PyObject* _0 = byte.arg == BC_NOARG ? POPX() : None;
|
||||||
_pop_frame();
|
_pop_frame();
|
||||||
if(frame.index == base_id){ // [ frameBase<- ]
|
if(frame == base_frame){ // [ frameBase<- ]
|
||||||
return _0;
|
return _0;
|
||||||
}else{
|
}else{
|
||||||
frame = top_frame();
|
frame = top_frame();
|
||||||
@ -826,16 +819,12 @@ __NEXT_STEP:;
|
|||||||
}catch(UnhandledException){
|
}catch(UnhandledException){
|
||||||
PyObject* e_obj = POPX();
|
PyObject* e_obj = POPX();
|
||||||
Exception& _e = PK_OBJ_GET(Exception, e_obj);
|
Exception& _e = PK_OBJ_GET(Exception, e_obj);
|
||||||
|
bool is_base_frame_to_be_popped = frame == base_frame;
|
||||||
_pop_frame();
|
_pop_frame();
|
||||||
if(callstack.empty()){
|
if(callstack.empty()) throw _e; // propagate to the top level
|
||||||
#if PK_DEBUG_FULL_EXCEPTION
|
|
||||||
std::cerr << _e.summary() << std::endl;
|
|
||||||
#endif
|
|
||||||
throw _e;
|
|
||||||
}
|
|
||||||
frame = top_frame();
|
frame = top_frame();
|
||||||
PUSH(e_obj);
|
PUSH(e_obj);
|
||||||
if(frame.index < base_id) throw ToBeRaisedException();
|
if(is_base_frame_to_be_popped) throw ToBeRaisedException();
|
||||||
need_raise = true;
|
need_raise = true;
|
||||||
}catch(ToBeRaisedException){
|
}catch(ToBeRaisedException){
|
||||||
need_raise = true;
|
need_raise = true;
|
||||||
|
|||||||
24
src/expr.cpp
24
src/expr.cpp
@ -64,6 +64,14 @@ namespace pkpy{
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CodeEmitContext::emit_int(i64 _val, int line){
|
||||||
|
if(is_imm_int(_val)){
|
||||||
|
return emit_(OP_LOAD_INTEGER, (uint16_t)_val, line);
|
||||||
|
}else{
|
||||||
|
return emit_(OP_LOAD_CONST, add_const(VAR(_val)), line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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].arg = target;
|
||||||
@ -246,11 +254,7 @@ namespace pkpy{
|
|||||||
VM* vm = ctx->vm;
|
VM* vm = ctx->vm;
|
||||||
if(std::holds_alternative<i64>(value)){
|
if(std::holds_alternative<i64>(value)){
|
||||||
i64 _val = std::get<i64>(value);
|
i64 _val = std::get<i64>(value);
|
||||||
if(is_imm_int(_val)){
|
ctx->emit_int(_val, line);
|
||||||
ctx->emit_(OP_LOAD_INTEGER, (uint16_t)_val, line);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(std::holds_alternative<f64>(value)){
|
if(std::holds_alternative<f64>(value)){
|
||||||
@ -272,11 +276,7 @@ namespace pkpy{
|
|||||||
LiteralExpr* lit = static_cast<LiteralExpr*>(child.get());
|
LiteralExpr* lit = static_cast<LiteralExpr*>(child.get());
|
||||||
if(std::holds_alternative<i64>(lit->value)){
|
if(std::holds_alternative<i64>(lit->value)){
|
||||||
i64 _val = -std::get<i64>(lit->value);
|
i64 _val = -std::get<i64>(lit->value);
|
||||||
if(is_imm_int(_val)){
|
ctx->emit_int(_val, line);
|
||||||
ctx->emit_(OP_LOAD_INTEGER, (uint16_t)_val, line);
|
|
||||||
}else{
|
|
||||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(std::holds_alternative<f64>(lit->value)){
|
if(std::holds_alternative<f64>(lit->value)){
|
||||||
@ -594,8 +594,8 @@ namespace pkpy{
|
|||||||
// vectorcall protocol
|
// vectorcall protocol
|
||||||
for(auto& item: args) item->emit_(ctx);
|
for(auto& item: args) item->emit_(ctx);
|
||||||
for(auto& item: kwargs){
|
for(auto& item: kwargs){
|
||||||
uint16_t index = StrName(item.first.sv()).index;
|
i64 _val = StrName(item.first.sv()).index;
|
||||||
ctx->emit_(OP_LOAD_INTEGER, index, line);
|
ctx->emit_int(_val, line);
|
||||||
item.second->emit_(ctx);
|
item.second->emit_(ctx);
|
||||||
}
|
}
|
||||||
int KWARGC = kwargs.size();
|
int KWARGC = kwargs.size();
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace pkpy{
|
|||||||
// restore the context
|
// restore the context
|
||||||
for(PyObject* obj: s_backup) vm->s_data.push(obj);
|
for(PyObject* obj: s_backup) vm->s_data.push(obj);
|
||||||
s_backup.clear();
|
s_backup.clear();
|
||||||
vm->callstack.push(std::move(frame));
|
vm->callstack.emplace(std::move(frame));
|
||||||
|
|
||||||
PyObject* ret;
|
PyObject* ret;
|
||||||
try{
|
try{
|
||||||
|
|||||||
@ -77,7 +77,7 @@ void init_builtins(VM* _vm) {
|
|||||||
class_arg = args[0];
|
class_arg = args[0];
|
||||||
self_arg = args[1];
|
self_arg = args[1];
|
||||||
}else if(args.size() == 0){
|
}else if(args.size() == 0){
|
||||||
FrameId frame = vm->top_frame();
|
Frame* frame = vm->top_frame();
|
||||||
if(frame->_callable != nullptr){
|
if(frame->_callable != nullptr){
|
||||||
class_arg = PK_OBJ_GET(Function, frame->_callable)._class;
|
class_arg = PK_OBJ_GET(Function, frame->_callable)._class;
|
||||||
if(frame->_locals.size() > 0) self_arg = frame->_locals[0];
|
if(frame->_locals.size() > 0) self_arg = frame->_locals[0];
|
||||||
@ -184,7 +184,7 @@ void init_builtins(VM* _vm) {
|
|||||||
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE, true);
|
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<eval>", EVAL_MODE, true);
|
||||||
PyObject* globals = args[1];
|
PyObject* globals = args[1];
|
||||||
if(globals == vm->None){
|
if(globals == vm->None){
|
||||||
FrameId frame = vm->top_frame();
|
Frame* frame = vm->top_frame();
|
||||||
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
return vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
||||||
}
|
}
|
||||||
vm->check_non_tagged_type(globals, vm->tp_mappingproxy);
|
vm->check_non_tagged_type(globals, vm->tp_mappingproxy);
|
||||||
@ -196,7 +196,7 @@ void init_builtins(VM* _vm) {
|
|||||||
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE, true);
|
CodeObject_ code = vm->compile(CAST(Str&, args[0]), "<exec>", EXEC_MODE, true);
|
||||||
PyObject* globals = args[1];
|
PyObject* globals = args[1];
|
||||||
if(globals == vm->None){
|
if(globals == vm->None){
|
||||||
FrameId frame = vm->top_frame();
|
Frame* frame = vm->top_frame();
|
||||||
vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,16 +18,17 @@ void LineProfiler::begin(){
|
|||||||
frames.clear();
|
frames.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineProfiler::_step(FrameId frame){
|
void LineProfiler::_step(LinkedFrame* linked_frame){
|
||||||
|
Frame* frame = &linked_frame->frame;
|
||||||
auto line_info = frame->co->lines[frame->_ip];
|
auto line_info = frame->co->lines[frame->_ip];
|
||||||
if(line_info.is_virtual) return;
|
if(line_info.is_virtual) return;
|
||||||
std::string_view filename = frame->co->src->filename.sv();
|
std::string_view filename = frame->co->src->filename.sv();
|
||||||
int line = line_info.lineno;
|
int line = line_info.lineno;
|
||||||
|
|
||||||
if(frames.empty()){
|
if(frames.empty()){
|
||||||
frames.push({frame, clock(), nullptr});
|
frames.push({linked_frame, clock(), nullptr});
|
||||||
}else{
|
}else{
|
||||||
_step_end(frame, line);
|
_step_end(linked_frame, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& file_records = records[filename];
|
auto& file_records = records[filename];
|
||||||
@ -43,13 +44,19 @@ void LineProfiler::_step(FrameId frame){
|
|||||||
frames.top().prev_record = &file_records.at(line);
|
frames.top().prev_record = &file_records.at(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineProfiler::_step_end(FrameId frame, int line){
|
void LineProfiler::_step_end(LinkedFrame* linked_frame, int line){
|
||||||
clock_t now = clock();
|
clock_t now = clock();
|
||||||
_FrameRecord& top_frame_record = frames.top();
|
_FrameRecord& top_frame_record = frames.top();
|
||||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||||
|
|
||||||
int id_delta = frame.index - top_frame_record.frame.index;
|
int id_delta;
|
||||||
PK_ASSERT(id_delta >= -1 && id_delta <= 1);
|
if(linked_frame == top_frame_record.frame){
|
||||||
|
id_delta = 0;
|
||||||
|
}else if(linked_frame->f_back == top_frame_record.frame){
|
||||||
|
id_delta = 1;
|
||||||
|
}else{
|
||||||
|
id_delta = -1; // unsafe
|
||||||
|
}
|
||||||
|
|
||||||
// current line is about to change
|
// current line is about to change
|
||||||
if(prev_record->line != line){
|
if(prev_record->line != line){
|
||||||
@ -60,7 +67,7 @@ void LineProfiler::_step_end(FrameId frame, int line){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(id_delta == 1){
|
if(id_delta == 1){
|
||||||
frames.push({frame, now, nullptr});
|
frames.push({linked_frame, now, nullptr});
|
||||||
}else{
|
}else{
|
||||||
if(id_delta == -1) frames.pop();
|
if(id_delta == -1) frames.pop();
|
||||||
}
|
}
|
||||||
|
|||||||
69
src/vm.cpp
69
src/vm.cpp
@ -119,16 +119,15 @@ namespace pkpy{
|
|||||||
PK_UNREACHABLE();
|
PK_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameId VM::top_frame(){
|
Frame* VM::top_frame(){
|
||||||
#if PK_DEBUG_EXTRA_CHECK
|
#if PK_DEBUG_EXTRA_CHECK
|
||||||
if(callstack.empty()) PK_FATAL_ERROR();
|
if(callstack.empty()) PK_FATAL_ERROR();
|
||||||
#endif
|
#endif
|
||||||
return FrameId(&callstack.container(), callstack.size()-1);
|
return &callstack.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM::_pop_frame(){
|
void VM::_pop_frame(){
|
||||||
Frame* frame = &callstack.top();
|
s_data.reset(callstack.top()._sp_base);
|
||||||
s_data.reset(frame->_sp_base);
|
|
||||||
callstack.pop();
|
callstack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +651,7 @@ void VM::_log_s_data(const char* title) {
|
|||||||
if(f._sp_base == nullptr) PK_FATAL_ERROR();
|
if(f._sp_base == nullptr) PK_FATAL_ERROR();
|
||||||
sp_bases[f._sp_base] += 1;
|
sp_bases[f._sp_base] += 1;
|
||||||
}
|
}
|
||||||
FrameId frame = top_frame();
|
Frame* frame = top_frame();
|
||||||
int line = frame->co->lines[frame->_ip];
|
int line = frame->co->lines[frame->_ip];
|
||||||
ss << frame->co->name << ":" << line << " [";
|
ss << frame->co->name << ":" << line << " [";
|
||||||
for(PyObject** p=s_data.begin(); p!=s_data.end(); p++){
|
for(PyObject** p=s_data.begin(); p!=s_data.end(); p++){
|
||||||
@ -838,7 +837,7 @@ void VM::_prepare_py_call(PyObject** buffer, ArgsView args, ArgsView kwargs, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int j=0; j<kwargs.size(); j+=2){
|
for(int j=0; j<kwargs.size(); j+=2){
|
||||||
StrName key(CAST(int, kwargs[j]));
|
StrName key(_CAST(uint16_t, kwargs[j]));
|
||||||
int index = decl->kw_to_index.try_get_likely_found(key);
|
int index = decl->kw_to_index.try_get_likely_found(key);
|
||||||
// if key is an explicit key, set as local variable
|
// if key is an explicit key, set as local variable
|
||||||
if(index >= 0){
|
if(index >= 0){
|
||||||
@ -861,13 +860,16 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
|||||||
// [callable, <self>, args..., kwargs...]
|
// [callable, <self>, args..., kwargs...]
|
||||||
// ^p0 ^p1 ^_sp
|
// ^p0 ^p1 ^_sp
|
||||||
PyObject* callable = p1[-(ARGC + 2)];
|
PyObject* callable = p1[-(ARGC + 2)];
|
||||||
|
Type callable_t = _tp(callable);
|
||||||
|
|
||||||
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
bool method_call = p1[-(ARGC + 1)] != PY_NULL;
|
||||||
|
|
||||||
// handle boundmethod, do a patch
|
// handle boundmethod, do a patch
|
||||||
if(is_non_tagged_type(callable, tp_bound_method)){
|
if(callable_t == tp_bound_method){
|
||||||
if(method_call) PK_FATAL_ERROR();
|
if(method_call) PK_FATAL_ERROR();
|
||||||
BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
|
BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
|
||||||
callable = bm.func; // get unbound method
|
callable = bm.func; // get unbound method
|
||||||
|
callable_t = _tp(callable);
|
||||||
p1[-(ARGC + 2)] = bm.func;
|
p1[-(ARGC + 2)] = bm.func;
|
||||||
p1[-(ARGC + 1)] = bm.self;
|
p1[-(ARGC + 1)] = bm.self;
|
||||||
method_call = true;
|
method_call = true;
|
||||||
@ -880,26 +882,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
|||||||
PyObject** _base = args.begin();
|
PyObject** _base = args.begin();
|
||||||
PyObject* buffer[PK_MAX_CO_VARNAMES];
|
PyObject* buffer[PK_MAX_CO_VARNAMES];
|
||||||
|
|
||||||
if(is_non_tagged_type(callable, tp_native_func)){
|
if(callable_t == tp_function){
|
||||||
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
|
||||||
PyObject* ret;
|
|
||||||
if(f.decl != nullptr){
|
|
||||||
int co_nlocals = f.decl->code->varnames.size();
|
|
||||||
_prepare_py_call(buffer, args, kwargs, f.decl);
|
|
||||||
// copy buffer back to stack
|
|
||||||
s_data.reset(_base + co_nlocals);
|
|
||||||
for(int j=0; j<co_nlocals; j++) _base[j] = buffer[j];
|
|
||||||
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
|
||||||
}else{
|
|
||||||
if(KWARGC != 0) TypeError("old-style native_func does not accept keyword arguments");
|
|
||||||
f.check_size(this, args);
|
|
||||||
ret = f.call(this, args);
|
|
||||||
}
|
|
||||||
s_data.reset(p0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_non_tagged_type(callable, tp_function)){
|
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
// callable must be a `function` object
|
// callable must be a `function` object
|
||||||
if(s_data.is_overflow()) StackOverflowError();
|
if(s_data.is_overflow()) StackOverflowError();
|
||||||
@ -931,7 +914,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
|||||||
if(co->is_generator){
|
if(co->is_generator){
|
||||||
s_data.reset(p0);
|
s_data.reset(p0);
|
||||||
return _py_generator(
|
return _py_generator(
|
||||||
Frame(nullptr, co, fn._module, callable),
|
Frame(nullptr, co, fn._module, callable, nullptr),
|
||||||
ArgsView(buffer, buffer + co_nlocals)
|
ArgsView(buffer, buffer + co_nlocals)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -941,13 +924,32 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
|||||||
for(int j=0; j<co_nlocals; j++) _base[j] = buffer[j];
|
for(int j=0; j<co_nlocals; j++) _base[j] = buffer[j];
|
||||||
|
|
||||||
__FAST_CALL:
|
__FAST_CALL:
|
||||||
callstack.emplace(p0, co, fn._module, callable, FastLocals(co, args.begin()));
|
callstack.emplace(p0, co, fn._module, callable, args.begin());
|
||||||
if(op_call) return PY_OP_CALL;
|
if(op_call) return PY_OP_CALL;
|
||||||
return _run_top_frame();
|
return _run_top_frame();
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_non_tagged_type(callable, tp_type)){
|
if(callable_t == tp_native_func){
|
||||||
|
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||||
|
PyObject* ret;
|
||||||
|
if(f.decl != nullptr){
|
||||||
|
int co_nlocals = f.decl->code->varnames.size();
|
||||||
|
_prepare_py_call(buffer, args, kwargs, f.decl);
|
||||||
|
// copy buffer back to stack
|
||||||
|
s_data.reset(_base + co_nlocals);
|
||||||
|
for(int j=0; j<co_nlocals; j++) _base[j] = buffer[j];
|
||||||
|
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
||||||
|
}else{
|
||||||
|
if(KWARGC != 0) TypeError("old-style native_func does not accept keyword arguments");
|
||||||
|
f.check_size(this, args);
|
||||||
|
ret = f.call(this, args);
|
||||||
|
}
|
||||||
|
s_data.reset(p0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(callable_t == tp_type){
|
||||||
// [type, NULL, args..., kwargs...]
|
// [type, NULL, args..., kwargs...]
|
||||||
PyObject* new_f = find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
|
PyObject* new_f = find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
|
||||||
PyObject* obj;
|
PyObject* obj;
|
||||||
@ -970,6 +972,7 @@ __FAST_CALL:
|
|||||||
// __init__
|
// __init__
|
||||||
PyObject* self;
|
PyObject* self;
|
||||||
callable = get_unbound_method(obj, __init__, &self, false);
|
callable = get_unbound_method(obj, __init__, &self, false);
|
||||||
|
callable_t = _tp(callable);
|
||||||
if (self != PY_NULL) {
|
if (self != PY_NULL) {
|
||||||
// replace `NULL` with `self`
|
// replace `NULL` with `self`
|
||||||
p1[-(ARGC + 2)] = callable;
|
p1[-(ARGC + 2)] = callable;
|
||||||
@ -994,7 +997,7 @@ __FAST_CALL:
|
|||||||
// [call_f, self, args..., kwargs...]
|
// [call_f, self, args..., kwargs...]
|
||||||
return vectorcall(ARGC, KWARGC, false);
|
return vectorcall(ARGC, KWARGC, false);
|
||||||
}
|
}
|
||||||
TypeError(_type_name(vm, _tp(callable)).escape() + " object is not callable");
|
TypeError(_type_name(vm, callable_t).escape() + " object is not callable");
|
||||||
PK_UNREACHABLE()
|
PK_UNREACHABLE()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1238,7 +1241,7 @@ void VM::_error(PyObject* e_obj){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VM::_raise(bool re_raise){
|
void VM::_raise(bool re_raise){
|
||||||
Frame* frame = top_frame().get();
|
Frame* frame = top_frame();
|
||||||
Exception& e = PK_OBJ_GET(Exception, s_data.top());
|
Exception& e = PK_OBJ_GET(Exception, s_data.top());
|
||||||
if(!re_raise){
|
if(!re_raise){
|
||||||
e._ip_on_error = frame->_ip;
|
e._ip_on_error = frame->_ip;
|
||||||
@ -1259,7 +1262,7 @@ void VM::_raise(bool re_raise){
|
|||||||
|
|
||||||
void ManagedHeap::mark() {
|
void ManagedHeap::mark() {
|
||||||
for(PyObject* obj: _no_gc) PK_OBJ_MARK(obj);
|
for(PyObject* obj: _no_gc) PK_OBJ_MARK(obj);
|
||||||
for(auto& frame : vm->callstack.container()) frame._gc_mark();
|
vm->callstack.apply([](Frame& frame){ frame._gc_mark(); });
|
||||||
for(PyObject* obj: vm->s_data) PK_OBJ_MARK(obj);
|
for(PyObject* obj: vm->s_data) PK_OBJ_MARK(obj);
|
||||||
for(auto [_, co]: vm->_cached_codes) co->_gc_mark();
|
for(auto [_, co]: vm->_cached_codes) co->_gc_mark();
|
||||||
if(vm->_last_exception) PK_OBJ_MARK(vm->_last_exception);
|
if(vm->_last_exception) PK_OBJ_MARK(vm->_last_exception);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user