add TraceInfo

This commit is contained in:
blueloveTH 2025-03-06 00:05:10 +08:00
parent 46f9e4ed4f
commit 64a4ae4676
7 changed files with 64 additions and 68 deletions

View File

@ -18,6 +18,16 @@
// 5. stack effect of each opcode
// 6. py_TypeInfo
typedef struct SourceLocation {
SourceData_ src;
int lineno;
} SourceLocation;
typedef struct TraceInfo {
SourceLocation prev_loc;
py_TraceFunc tracefunc;
} TraceInfo;
typedef struct VM {
Frame* top_frame;
@ -38,9 +48,10 @@ typedef struct VM {
py_TValue reg[8]; // users' registers
void* ctx; // user-defined context
py_StackRef __curr_class;
py_StackRef __curr_function;
py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES];
py_StackRef curr_class;
py_StackRef curr_function;
TraceInfo trace_info;
py_TValue vectorcall_buffer[PK_MAX_CO_VARNAMES];
InternedNames names;
FixedMemoryPool pool_frame;

View File

@ -34,45 +34,6 @@ typedef struct c11_sv {
int size;
} 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_RETURN
@ -89,6 +50,28 @@ typedef py_TValue* py_ItemRef;
/// An output reference for returning a value.
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.
/// @param argc number of arguments.
/// @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);
/// Set `sys.argv`. Used for storing command-line arguments.
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.
PK_API py_Callbacks* py_callbacks();

View File

@ -1046,7 +1046,7 @@ void CallExpr__emit_(Expr* self_, Ctx* ctx) {
Opcode opcode = OP_CALL;
if(vargs || vkwargs) {
// 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;
}

View File

@ -97,7 +97,7 @@ FrameResult VM__run_top_frame(VM* self) {
frame->ip++;
__NEXT_STEP:
if(self->callbacks.tracefunc) {
if(self->trace_info.tracefunc) {
// TODO: implement tracing mechanism
}
@ -298,9 +298,9 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH();
}
case OP_LOAD_CLASS_GLOBAL: {
assert(self->__curr_class);
assert(self->curr_class);
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) {
PUSH(tmp);
DISPATCH();
@ -691,7 +691,7 @@ FrameResult VM__run_top_frame(VM* self) {
py_TValue* sp = SP();
py_TValue* p1 = sp - kwargc * 2;
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++) {
if(curr->type != tp_star_wrapper) {
@ -1008,7 +1008,7 @@ FrameResult VM__run_top_frame(VM* self) {
base_ti->is_python,
false);
PUSH(py_tpobject(type));
self->__curr_class = TOP();
self->curr_class = TOP();
DISPATCH();
}
case OP_END_CLASS: {
@ -1033,11 +1033,11 @@ FrameResult VM__run_top_frame(VM* self) {
// class with decorator is unsafe currently
// it skips the above check
POP();
self->__curr_class = NULL;
self->curr_class = NULL;
DISPATCH();
}
case OP_STORE_CLASS_ATTR: {
assert(self->__curr_class);
assert(self->curr_class);
py_Name name = byte.arg;
// TOP() can be a function, classmethod or custom decorator
py_Ref actual_func = TOP();
@ -1046,16 +1046,16 @@ FrameResult VM__run_top_frame(VM* self) {
}
if(actual_func->type == tp_function) {
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();
DISPATCH();
}
case OP_ADD_CLASS_ANNOTATION: {
assert(self->__curr_class);
assert(self->curr_class);
// [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);
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations);
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());

View File

@ -68,15 +68,15 @@ void VM__ctor(VM* self) {
self->callbacks.importfile = pk_default_importfile;
self->callbacks.print = pk_default_print;
self->callbacks.getchar = getchar;
self->callbacks.tracefunc = NULL;
self->last_retval = *py_NIL();
self->curr_exception = *py_NIL();
self->is_curr_exc_handled = false;
self->ctx = NULL;
self->__curr_class = NULL;
self->__curr_function = NULL;
self->curr_class = NULL;
self->curr_function = NULL;
memset(&self->trace_info, 0, sizeof(TraceInfo));
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) {
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;
// copy buffer back to stack
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
if(!fn->cfunc) {
// 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);
} else {
// decl-based binding
self->__curr_function = p0;
self->curr_function = p0;
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
self->stack.sp = p0;
self->__curr_function = NULL;
self->curr_function = NULL;
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);
} else {
// decl-based binding
self->__curr_function = p0;
self->curr_function = p0;
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
self->stack.sp = p0;
self->__curr_function = NULL;
self->curr_function = NULL;
return ok ? RES_RETURN : RES_ERROR;
}
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;
// copy buffer back to stack
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);
pk_newgenerator(py_retval(), frame, p0, self->stack.sp);
self->stack.sp = p0; // reset the stack

View File

@ -154,8 +154,8 @@ void py_clearexc(py_StackRef p0) {
vm->curr_exception = *py_NIL();
vm->is_curr_exc_handled = false;
/* Don't clear this, because StopIteration() may corrupt the class definition */
// vm->__curr_class = NULL;
vm->__curr_function = NULL;
// vm->curr_class = NULL;
vm->curr_function = NULL;
if(p0) vm->stack.sp = p0;
}

View File

@ -69,7 +69,7 @@ void py_setslot(py_Ref self, int i, py_Ref val) {
}
py_StackRef py_inspect_currentfunction(){
return pk_current_vm->__curr_function;
return pk_current_vm->curr_function;
}
py_GlobalRef py_inspect_currentmodule(){