mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
add TraceInfo
This commit is contained in:
parent
46f9e4ed4f
commit
64a4ae4676
@ -18,6 +18,16 @@
|
|||||||
// 5. stack effect of each opcode
|
// 5. stack effect of each opcode
|
||||||
// 6. py_TypeInfo
|
// 6. py_TypeInfo
|
||||||
|
|
||||||
|
typedef struct SourceLocation {
|
||||||
|
SourceData_ src;
|
||||||
|
int lineno;
|
||||||
|
} SourceLocation;
|
||||||
|
|
||||||
|
typedef struct TraceInfo {
|
||||||
|
SourceLocation prev_loc;
|
||||||
|
py_TraceFunc tracefunc;
|
||||||
|
} TraceInfo;
|
||||||
|
|
||||||
typedef struct VM {
|
typedef struct VM {
|
||||||
Frame* top_frame;
|
Frame* top_frame;
|
||||||
|
|
||||||
@ -38,9 +48,10 @@ typedef struct VM {
|
|||||||
py_TValue reg[8]; // users' registers
|
py_TValue reg[8]; // users' registers
|
||||||
void* ctx; // user-defined context
|
void* ctx; // user-defined context
|
||||||
|
|
||||||
py_StackRef __curr_class;
|
py_StackRef curr_class;
|
||||||
py_StackRef __curr_function;
|
py_StackRef curr_function;
|
||||||
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
TraceInfo trace_info;
|
||||||
|
py_TValue vectorcall_buffer[PK_MAX_CO_VARNAMES];
|
||||||
|
|
||||||
InternedNames names;
|
InternedNames names;
|
||||||
FixedMemoryPool pool_frame;
|
FixedMemoryPool pool_frame;
|
||||||
|
@ -34,45 +34,6 @@ typedef struct c11_sv {
|
|||||||
int size;
|
int size;
|
||||||
} c11_sv;
|
} c11_sv;
|
||||||
|
|
||||||
// An enum for tracing events.
|
|
||||||
enum py_TraceEvent {
|
|
||||||
TraceEvent_Line,
|
|
||||||
TraceEvent_Call,
|
|
||||||
TraceEvent_Return,
|
|
||||||
TraceEvent_Exception,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A struct contains the arguments of the tracing event.
|
|
||||||
union py_TraceEventArg {
|
|
||||||
struct {
|
|
||||||
int _;
|
|
||||||
} line;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int _;
|
|
||||||
} call;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int _;
|
|
||||||
} return_;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int _;
|
|
||||||
} exception;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A struct contains the callbacks of the VM.
|
|
||||||
typedef struct py_Callbacks {
|
|
||||||
/// Used by `__import__` to load source code of a module.
|
|
||||||
char* (*importfile)(const char*);
|
|
||||||
/// Used by `print` to output a string.
|
|
||||||
void (*print)(const char*);
|
|
||||||
/// Used by `input` to get a character.
|
|
||||||
int (*getchar)();
|
|
||||||
/// C-style `sys.settrace` function.
|
|
||||||
void (*tracefunc)(enum py_TraceEvent, union py_TraceEventArg);
|
|
||||||
} py_Callbacks;
|
|
||||||
|
|
||||||
#define PY_RAISE
|
#define PY_RAISE
|
||||||
#define PY_RETURN
|
#define PY_RETURN
|
||||||
|
|
||||||
@ -89,6 +50,28 @@ typedef py_TValue* py_ItemRef;
|
|||||||
/// An output reference for returning a value.
|
/// An output reference for returning a value.
|
||||||
typedef py_TValue* py_OutRef;
|
typedef py_TValue* py_OutRef;
|
||||||
|
|
||||||
|
typedef struct py_Frame py_Frame;
|
||||||
|
|
||||||
|
// An enum for tracing events.
|
||||||
|
enum py_TraceEvent {
|
||||||
|
TRACE_EVENT_LINE,
|
||||||
|
TRACE_EVENT_CALL,
|
||||||
|
TRACE_EVENT_RETURN,
|
||||||
|
TRACE_EVENT_EXCEPTION,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*py_TraceFunc)(py_Frame* frame, enum py_TraceEvent);
|
||||||
|
|
||||||
|
/// A struct contains the callbacks of the VM.
|
||||||
|
typedef struct py_Callbacks {
|
||||||
|
/// Used by `__import__` to load source code of a module.
|
||||||
|
char* (*importfile)(const char*);
|
||||||
|
/// Used by `print` to output a string.
|
||||||
|
void (*print)(const char*);
|
||||||
|
/// Used by `input` to get a character.
|
||||||
|
int (*getchar)();
|
||||||
|
} py_Callbacks;
|
||||||
|
|
||||||
/// Native function signature.
|
/// Native function signature.
|
||||||
/// @param argc number of arguments.
|
/// @param argc number of arguments.
|
||||||
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
|
||||||
@ -120,6 +103,8 @@ PK_API void* py_getvmctx();
|
|||||||
PK_API void py_setvmctx(void* ctx);
|
PK_API void py_setvmctx(void* ctx);
|
||||||
/// Set `sys.argv`. Used for storing command-line arguments.
|
/// Set `sys.argv`. Used for storing command-line arguments.
|
||||||
PK_API void py_sys_setargv(int argc, char** argv);
|
PK_API void py_sys_setargv(int argc, char** argv);
|
||||||
|
/// Set the trace function for the current VM.
|
||||||
|
PK_API void py_sys_settrace(py_TraceFunc func);
|
||||||
/// Setup the callbacks for the current VM.
|
/// Setup the callbacks for the current VM.
|
||||||
PK_API py_Callbacks* py_callbacks();
|
PK_API py_Callbacks* py_callbacks();
|
||||||
|
|
||||||
|
@ -1046,7 +1046,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
|
|||||||
Opcode opcode = OP_CALL;
|
Opcode opcode = OP_CALL;
|
||||||
if(vargs || vkwargs) {
|
if(vargs || vkwargs) {
|
||||||
// in this case, there is at least one *args or **kwargs as StarredExpr
|
// in this case, there is at least one *args or **kwargs as StarredExpr
|
||||||
// OP_CALL_VARGS needs to unpack them via __vectorcall_buffer
|
// OP_CALL_VARGS needs to unpack them via vectorcall_buffer
|
||||||
opcode = OP_CALL_VARGS;
|
opcode = OP_CALL_VARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
frame->ip++;
|
frame->ip++;
|
||||||
|
|
||||||
__NEXT_STEP:
|
__NEXT_STEP:
|
||||||
if(self->callbacks.tracefunc) {
|
if(self->trace_info.tracefunc) {
|
||||||
// TODO: implement tracing mechanism
|
// TODO: implement tracing mechanism
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,9 +298,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_LOAD_CLASS_GLOBAL: {
|
case OP_LOAD_CLASS_GLOBAL: {
|
||||||
assert(self->__curr_class);
|
assert(self->curr_class);
|
||||||
py_Name name = byte.arg;
|
py_Name name = byte.arg;
|
||||||
py_Ref tmp = py_getdict(self->__curr_class, name);
|
py_Ref tmp = py_getdict(self->curr_class, name);
|
||||||
if(tmp) {
|
if(tmp) {
|
||||||
PUSH(tmp);
|
PUSH(tmp);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
@ -691,7 +691,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
py_TValue* sp = SP();
|
py_TValue* sp = SP();
|
||||||
py_TValue* p1 = sp - kwargc * 2;
|
py_TValue* p1 = sp - kwargc * 2;
|
||||||
py_TValue* base = p1 - argc;
|
py_TValue* base = p1 - argc;
|
||||||
py_TValue* buf = self->__vectorcall_buffer;
|
py_TValue* buf = self->vectorcall_buffer;
|
||||||
|
|
||||||
for(py_TValue* curr = base; curr != p1; curr++) {
|
for(py_TValue* curr = base; curr != p1; curr++) {
|
||||||
if(curr->type != tp_star_wrapper) {
|
if(curr->type != tp_star_wrapper) {
|
||||||
@ -1008,7 +1008,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
base_ti->is_python,
|
base_ti->is_python,
|
||||||
false);
|
false);
|
||||||
PUSH(py_tpobject(type));
|
PUSH(py_tpobject(type));
|
||||||
self->__curr_class = TOP();
|
self->curr_class = TOP();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_END_CLASS: {
|
case OP_END_CLASS: {
|
||||||
@ -1033,11 +1033,11 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
// class with decorator is unsafe currently
|
// class with decorator is unsafe currently
|
||||||
// it skips the above check
|
// it skips the above check
|
||||||
POP();
|
POP();
|
||||||
self->__curr_class = NULL;
|
self->curr_class = NULL;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_STORE_CLASS_ATTR: {
|
case OP_STORE_CLASS_ATTR: {
|
||||||
assert(self->__curr_class);
|
assert(self->curr_class);
|
||||||
py_Name name = byte.arg;
|
py_Name name = byte.arg;
|
||||||
// TOP() can be a function, classmethod or custom decorator
|
// TOP() can be a function, classmethod or custom decorator
|
||||||
py_Ref actual_func = TOP();
|
py_Ref actual_func = TOP();
|
||||||
@ -1046,16 +1046,16 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
}
|
}
|
||||||
if(actual_func->type == tp_function) {
|
if(actual_func->type == tp_function) {
|
||||||
Function* ud = py_touserdata(actual_func);
|
Function* ud = py_touserdata(actual_func);
|
||||||
ud->clazz = self->__curr_class->_obj;
|
ud->clazz = self->curr_class->_obj;
|
||||||
}
|
}
|
||||||
py_setdict(self->__curr_class, name, TOP());
|
py_setdict(self->curr_class, name, TOP());
|
||||||
POP();
|
POP();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_ADD_CLASS_ANNOTATION: {
|
case OP_ADD_CLASS_ANNOTATION: {
|
||||||
assert(self->__curr_class);
|
assert(self->curr_class);
|
||||||
// [type_hint string]
|
// [type_hint string]
|
||||||
py_Type type = py_totype(self->__curr_class);
|
py_Type type = py_totype(self->curr_class);
|
||||||
py_TypeInfo* ti = TypeList__get(&self->types, type);
|
py_TypeInfo* ti = TypeList__get(&self->types, type);
|
||||||
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
|
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
|
||||||
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());
|
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());
|
||||||
|
@ -68,15 +68,15 @@ void VM__ctor(VM* self) {
|
|||||||
self->callbacks.importfile = pk_default_importfile;
|
self->callbacks.importfile = pk_default_importfile;
|
||||||
self->callbacks.print = pk_default_print;
|
self->callbacks.print = pk_default_print;
|
||||||
self->callbacks.getchar = getchar;
|
self->callbacks.getchar = getchar;
|
||||||
self->callbacks.tracefunc = NULL;
|
|
||||||
|
|
||||||
self->last_retval = *py_NIL();
|
self->last_retval = *py_NIL();
|
||||||
self->curr_exception = *py_NIL();
|
self->curr_exception = *py_NIL();
|
||||||
self->is_curr_exc_handled = false;
|
self->is_curr_exc_handled = false;
|
||||||
|
|
||||||
self->ctx = NULL;
|
self->ctx = NULL;
|
||||||
self->__curr_class = NULL;
|
self->curr_class = NULL;
|
||||||
self->__curr_function = NULL;
|
self->curr_function = NULL;
|
||||||
|
memset(&self->trace_info, 0, sizeof(TraceInfo));
|
||||||
|
|
||||||
FixedMemoryPool__ctor(&self->pool_frame, sizeof(Frame), 32);
|
FixedMemoryPool__ctor(&self->pool_frame, sizeof(Frame), 32);
|
||||||
|
|
||||||
@ -479,11 +479,11 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
|
|
||||||
switch(fn->decl->type) {
|
switch(fn->decl->type) {
|
||||||
case FuncType_NORMAL: {
|
case FuncType_NORMAL: {
|
||||||
bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
bool ok = prepare_py_call(self->vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
||||||
if(!ok) return RES_ERROR;
|
if(!ok) return RES_ERROR;
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
self->stack.sp = argv + co->nlocals;
|
self->stack.sp = argv + co->nlocals;
|
||||||
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
memcpy(argv, self->vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
||||||
// submit the call
|
// submit the call
|
||||||
if(!fn->cfunc) {
|
if(!fn->cfunc) {
|
||||||
// python function
|
// python function
|
||||||
@ -491,10 +491,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
return opcall ? RES_CALL : VM__run_top_frame(self);
|
return opcall ? RES_CALL : VM__run_top_frame(self);
|
||||||
} else {
|
} else {
|
||||||
// decl-based binding
|
// decl-based binding
|
||||||
self->__curr_function = p0;
|
self->curr_function = p0;
|
||||||
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
|
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
|
||||||
self->stack.sp = p0;
|
self->stack.sp = p0;
|
||||||
self->__curr_function = NULL;
|
self->curr_function = NULL;
|
||||||
return ok ? RES_RETURN : RES_ERROR;
|
return ok ? RES_RETURN : RES_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,18 +520,18 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
return opcall ? RES_CALL : VM__run_top_frame(self);
|
return opcall ? RES_CALL : VM__run_top_frame(self);
|
||||||
} else {
|
} else {
|
||||||
// decl-based binding
|
// decl-based binding
|
||||||
self->__curr_function = p0;
|
self->curr_function = p0;
|
||||||
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
|
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
|
||||||
self->stack.sp = p0;
|
self->stack.sp = p0;
|
||||||
self->__curr_function = NULL;
|
self->curr_function = NULL;
|
||||||
return ok ? RES_RETURN : RES_ERROR;
|
return ok ? RES_RETURN : RES_ERROR;
|
||||||
}
|
}
|
||||||
case FuncType_GENERATOR: {
|
case FuncType_GENERATOR: {
|
||||||
bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
bool ok = prepare_py_call(self->vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
||||||
if(!ok) return RES_ERROR;
|
if(!ok) return RES_ERROR;
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
self->stack.sp = argv + co->nlocals;
|
self->stack.sp = argv + co->nlocals;
|
||||||
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
memcpy(argv, self->vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
||||||
Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, false);
|
Frame* frame = Frame__new(co, p0, fn->module, fn->globals, argv, false);
|
||||||
pk_newgenerator(py_retval(), frame, p0, self->stack.sp);
|
pk_newgenerator(py_retval(), frame, p0, self->stack.sp);
|
||||||
self->stack.sp = p0; // reset the stack
|
self->stack.sp = p0; // reset the stack
|
||||||
|
@ -154,8 +154,8 @@ void py_clearexc(py_StackRef p0) {
|
|||||||
vm->curr_exception = *py_NIL();
|
vm->curr_exception = *py_NIL();
|
||||||
vm->is_curr_exc_handled = false;
|
vm->is_curr_exc_handled = false;
|
||||||
/* Don't clear this, because StopIteration() may corrupt the class definition */
|
/* Don't clear this, because StopIteration() may corrupt the class definition */
|
||||||
// vm->__curr_class = NULL;
|
// vm->curr_class = NULL;
|
||||||
vm->__curr_function = NULL;
|
vm->curr_function = NULL;
|
||||||
if(p0) vm->stack.sp = p0;
|
if(p0) vm->stack.sp = p0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ void py_setslot(py_Ref self, int i, py_Ref val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
py_StackRef py_inspect_currentfunction(){
|
py_StackRef py_inspect_currentfunction(){
|
||||||
return pk_current_vm->__curr_function;
|
return pk_current_vm->curr_function;
|
||||||
}
|
}
|
||||||
|
|
||||||
py_GlobalRef py_inspect_currentmodule(){
|
py_GlobalRef py_inspect_currentmodule(){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user