tracy
This commit is contained in:
251
source/quickjs.c
251
source/quickjs.c
@@ -378,6 +378,112 @@ struct JSGCObjectHeader {
|
|||||||
struct list_head link;
|
struct list_head link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mist_obj_type {
|
||||||
|
OBJ_ARRAY = 0,
|
||||||
|
OBJ_BLOB = 1,
|
||||||
|
OBJ_TEXT = 2,
|
||||||
|
OBJ_RECORD = 3,
|
||||||
|
OBJ_FUNCTION= 4,
|
||||||
|
OBJ_CODE = 5,
|
||||||
|
OBJ_FRAME = 6,
|
||||||
|
OBJ_FORWARD = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OBJHDR_CAP_SHIFT 8u
|
||||||
|
#define OBJHDR_CAP_MASK (((objhdr_t)1ull << 56) - 1ull)
|
||||||
|
|
||||||
|
#define OBJHDR_S_BIT 3u
|
||||||
|
#define OBJHDR_P_BIT 4u
|
||||||
|
#define OBJHDR_A_BIT 5u
|
||||||
|
#define OBJHDR_R_BIT 7u
|
||||||
|
|
||||||
|
#define OBJHDR_FLAG(bit) ((objhdr_t)1ull << (bit))
|
||||||
|
#define OBJHDR_S_MASK OBJHDR_FLAG(OBJHDR_S_BIT)
|
||||||
|
#define OBJHDR_P_MASK OBJHDR_FLAG(OBJHDR_P_BIT)
|
||||||
|
#define OBJHDR_A_MASK OBJHDR_FLAG(OBJHDR_A_BIT)
|
||||||
|
#define OBJHDR_R_MASK OBJHDR_FLAG(OBJHDR_R_BIT)
|
||||||
|
|
||||||
|
typedef uint64_t word_t; // one actor-memory word
|
||||||
|
typedef uint64_t objhdr_t; // header word
|
||||||
|
typedef uint64_t objref_t; // 56-bit word address (0 = null)
|
||||||
|
|
||||||
|
static inline uint8_t objhdr_type(objhdr_t h) { return (uint8_t)(h & 7u); }
|
||||||
|
static inline bool objhdr_s(objhdr_t h) { return (h & OBJHDR_S_MASK) != 0; }
|
||||||
|
static inline uint64_t objhdr_cap56(objhdr_t h) {
|
||||||
|
return (uint64_t)((h >> OBJHDR_CAP_SHIFT) & OBJHDR_CAP_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline objhdr_t objhdr_make(uint64_t cap56, uint8_t type, bool r, bool a, bool p, bool s) {
|
||||||
|
objhdr_t h = 0;
|
||||||
|
h |= ((objhdr_t)(cap56 & OBJHDR_CAP_MASK)) << OBJHDR_CAP_SHIFT;
|
||||||
|
h |= (objhdr_t)(type & 7u);
|
||||||
|
if (s) h |= OBJHDR_S_MASK;
|
||||||
|
if (p) h |= OBJHDR_P_MASK;
|
||||||
|
if (a) h |= OBJHDR_A_MASK;
|
||||||
|
if (r) h |= OBJHDR_R_MASK;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Array:
|
||||||
|
[hdr(type=0, cap=element_capacity)]
|
||||||
|
[len]
|
||||||
|
[elem0..elem(cap-1)]
|
||||||
|
*/
|
||||||
|
typedef struct mist_array {
|
||||||
|
objhdr_t hdr;
|
||||||
|
word_t len;
|
||||||
|
word_t elem[]; // length 'cap' in words
|
||||||
|
} mist_array;
|
||||||
|
|
||||||
|
/* Blob:
|
||||||
|
[hdr(type=1, cap=bit_capacity)]
|
||||||
|
[len_bits]
|
||||||
|
[bitwords...], big-endian bit numbering per word (bit0 is MSB of first data word)
|
||||||
|
*/
|
||||||
|
typedef struct mist_blob {
|
||||||
|
objhdr_t hdr;
|
||||||
|
word_t len_bits;
|
||||||
|
word_t bits[]; // count = (cap + 63)/64
|
||||||
|
} mist_blob;
|
||||||
|
|
||||||
|
/* Text (type=2):
|
||||||
|
Pretext (mutable): s=0
|
||||||
|
[hdr(cap=char_capacity, s=0)]
|
||||||
|
[len_chars]
|
||||||
|
[packed UTF32 chars...]
|
||||||
|
Text (immutable): s=1
|
||||||
|
[hdr(cap=length, s=1)]
|
||||||
|
[hash (0 => not computed yet)]
|
||||||
|
[packed UTF32 chars...]
|
||||||
|
Packed: 2 UTF32 per word, high 32 then low 32.
|
||||||
|
*/
|
||||||
|
typedef struct mist_text {
|
||||||
|
objhdr_t hdr;
|
||||||
|
word_t len_or_hash;
|
||||||
|
word_t packed[]; // count = (cap + 1)/2
|
||||||
|
} mist_text;
|
||||||
|
|
||||||
|
/* Record (type=3):
|
||||||
|
Open-address table, slots 1..cap used, slot 0 reserved.
|
||||||
|
Capacity is (2^n - 1) mask; total slots = cap+1 (a power of two).
|
||||||
|
Layout words:
|
||||||
|
[hdr(cap=mask)]
|
||||||
|
[len_fields]
|
||||||
|
[key1][val1]...[key_cap][val_cap]
|
||||||
|
Total words = 2*(cap+1) (matches spec).
|
||||||
|
*/
|
||||||
|
typedef struct mist_slot {
|
||||||
|
word_t key; // typically objref_t to a TEXT object (must be immutable for stable hash)
|
||||||
|
word_t value; // any value word
|
||||||
|
} mist_slot;
|
||||||
|
|
||||||
|
typedef struct mist_record {
|
||||||
|
objhdr_t hdr;
|
||||||
|
word_t len_fields;
|
||||||
|
mist_slot slot[]; // slot[0] corresponds to field #1, ..., slot[cap-1] is field #cap
|
||||||
|
} mist_record;
|
||||||
|
|
||||||
|
|
||||||
#ifdef RC_TRACE
|
#ifdef RC_TRACE
|
||||||
typedef struct RcEvent {
|
typedef struct RcEvent {
|
||||||
JSGCObjectHeader *ptr;
|
JSGCObjectHeader *ptr;
|
||||||
@@ -10210,10 +10316,9 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
|||||||
func = f->u.cfunc.c_function;
|
func = f->u.cfunc.c_function;
|
||||||
|
|
||||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_CALL)) {
|
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_CALL)) {
|
||||||
js_debug dbg = {0};
|
js_debug dbg;
|
||||||
js_debug_info(ctx, func_obj, &dbg);
|
js_debug_info(ctx, func_obj, &dbg);
|
||||||
ctx->trace_hook(ctx, JS_HOOK_CALL, &dbg, ctx->trace_data);
|
ctx->trace_hook(ctx, JS_HOOK_CALL, &dbg, ctx->trace_data);
|
||||||
free_js_debug_info(ctx, &dbg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(cproto) {
|
switch(cproto) {
|
||||||
@@ -10269,12 +10374,8 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
|||||||
|
|
||||||
rt->current_stack_frame = sf->prev_frame;
|
rt->current_stack_frame = sf->prev_frame;
|
||||||
|
|
||||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET)) {
|
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
||||||
js_debug dbg = {0};
|
ctx->trace_hook(ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
||||||
js_debug_info(ctx, func_obj, &dbg);
|
|
||||||
ctx->trace_hook(ctx, JS_HOOK_RET, &dbg, ctx->trace_data);
|
|
||||||
free_js_debug_info(ctx, &dbg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
@@ -10464,10 +10565,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_CALL)) {
|
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_CALL)) {
|
||||||
js_debug dbg = {0};
|
js_debug dbg;
|
||||||
js_debug_info(caller_ctx, func_obj, &dbg);
|
js_debug_info(caller_ctx, func_obj, &dbg);
|
||||||
caller_ctx->trace_hook(caller_ctx, JS_HOOK_CALL, &dbg, caller_ctx->trace_data);
|
caller_ctx->trace_hook(caller_ctx, JS_HOOK_CALL, &dbg, caller_ctx->trace_data);
|
||||||
free_js_debug_info(caller_ctx, &dbg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
|
if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
|
||||||
@@ -12655,12 +12755,8 @@ CASE(OP_template_concat):
|
|||||||
}
|
}
|
||||||
rt->current_stack_frame = sf->prev_frame;
|
rt->current_stack_frame = sf->prev_frame;
|
||||||
|
|
||||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_RET)) {
|
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_RET))
|
||||||
js_debug dbg = {0};
|
caller_ctx->trace_hook(caller_ctx, JS_HOOK_RET, NULL, caller_ctx->trace_data);
|
||||||
js_debug_info(caller_ctx, func_obj, &dbg);
|
|
||||||
caller_ctx->trace_hook(caller_ctx, JS_HOOK_RET, &dbg, caller_ctx->trace_data);
|
|
||||||
free_js_debug_info(caller_ctx, &dbg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
@@ -29106,16 +29202,9 @@ static JSValue js_blob_wf(JSContext *ctx, JSValueConst this_val, JSValueConst ar
|
|||||||
if (!bd) return JS_ThrowTypeError(ctx, "wf: not called on a blob");
|
if (!bd) return JS_ThrowTypeError(ctx, "wf: not called on a blob");
|
||||||
|
|
||||||
float f;
|
float f;
|
||||||
int tag = JS_VALUE_GET_TAG(arg0);
|
double d;
|
||||||
if (tag == JS_TAG_INT) {
|
if (JS_ToFloat64(ctx, &d, arg0) < 0) return JS_EXCEPTION;
|
||||||
f = (float)JS_VALUE_GET_INT(arg0);
|
f = d;
|
||||||
} else if (tag == JS_TAG_FLOAT64) {
|
|
||||||
f = (float)JS_VALUE_GET_FLOAT64(arg0);
|
|
||||||
} else {
|
|
||||||
double d;
|
|
||||||
if (JS_ToFloat64(ctx, &d, arg0) < 0) return JS_EXCEPTION;
|
|
||||||
f = (float)d;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blob_write_bytes(bd, &f, sizeof(f)) < 0)
|
if (blob_write_bytes(bd, &f, sizeof(f)) < 0)
|
||||||
return JS_ThrowTypeError(ctx, "wf: cannot write");
|
return JS_ThrowTypeError(ctx, "wf: cannot write");
|
||||||
@@ -30246,76 +30335,58 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
|||||||
#define STRLEN(s) (sizeof(s)/sizeof(s[0]))
|
#define STRLEN(s) (sizeof(s)/sizeof(s[0]))
|
||||||
#define CSTR "<native C>"
|
#define CSTR "<native C>"
|
||||||
|
|
||||||
void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
|
static inline void atom_to_buf(JSContext *ctx, JSAtom atom, char *dst, int cap, const char *fallback)
|
||||||
{
|
{
|
||||||
memset(dbg, 0, sizeof(*dbg));
|
if (atom == JS_ATOM_NULL) {
|
||||||
|
strncpy(dst, fallback, cap);
|
||||||
if (!JS_IsFunction(fn)) return;
|
dst[cap - 1] = 0;
|
||||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
return;
|
||||||
|
|
||||||
const char *fn_name = NULL;
|
|
||||||
if (f->name != JS_ATOM_NULL) {
|
|
||||||
fn_name = JS_AtomToCString(js, f->name);
|
|
||||||
} else if (f->kind == JS_FUNC_KIND_BYTECODE && f->u.func.function_bytecode) {
|
|
||||||
fn_name = JS_AtomToCString(js, f->u.func.function_bytecode->func_name);
|
|
||||||
}
|
}
|
||||||
|
JS_AtomGetStr(ctx, dst, cap, atom);
|
||||||
if (!fn_name)
|
if (dst[0] == 0) {
|
||||||
dbg->name = js_strdup(js, "<anonymous>");
|
strncpy(dst, fallback, cap);
|
||||||
else if (fn_name[0] == 0) {
|
dst[cap - 1] = 0;
|
||||||
dbg->name = js_strdup(js, "<anonymous>");
|
|
||||||
JS_FreeCString(js,fn_name);
|
|
||||||
} else {
|
|
||||||
dbg->name = js_strdup(js, fn_name);
|
|
||||||
JS_FreeCString(js,fn_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg->unique = (int)(uintptr_t)f;
|
|
||||||
|
|
||||||
switch(f->kind) {
|
|
||||||
case JS_FUNC_KIND_BYTECODE: {
|
|
||||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
|
||||||
// get filename
|
|
||||||
const char *filename = JS_AtomToCString(js, b->debug.filename);
|
|
||||||
if (!filename)
|
|
||||||
dbg->filename = js_strdup(js, "unknown");
|
|
||||||
else if (filename[0] == 0) {
|
|
||||||
dbg->filename = js_strdup(js, "unknown");
|
|
||||||
JS_FreeCString(js,filename);
|
|
||||||
} else {
|
|
||||||
dbg->filename = js_strdup(js, filename);
|
|
||||||
JS_FreeCString(js,filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg->what = "JS";
|
|
||||||
dbg->closure_n = b->closure_var_count;
|
|
||||||
dbg->param_n = b->arg_count;
|
|
||||||
dbg->vararg = 1;
|
|
||||||
int pcol_num;
|
|
||||||
dbg->line = find_line_num(js, b, -1, &pcol_num);
|
|
||||||
dbg->source = b->debug.source;
|
|
||||||
dbg->srclen = b->debug.source_len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JS_FUNC_KIND_C:
|
|
||||||
case JS_FUNC_KIND_C_DATA:
|
|
||||||
dbg->filename = js_strdup(js, "<native C>");
|
|
||||||
dbg->what = "C";
|
|
||||||
dbg->nparams = f->length;
|
|
||||||
dbg->vararg = 1;
|
|
||||||
dbg->line = 0;
|
|
||||||
dbg->source = CSTR;
|
|
||||||
dbg->srclen = STRLEN(CSTR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_js_debug_info(JSContext *js, js_debug *dbg)
|
void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
|
||||||
{
|
{
|
||||||
js_free(js, dbg->filename);
|
*dbg = (js_debug){0};
|
||||||
js_free(js, dbg->name);
|
|
||||||
|
if (!JS_IsFunction(fn)) return;
|
||||||
|
|
||||||
|
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||||
|
dbg->unique = (int)(uintptr_t)f;
|
||||||
|
|
||||||
|
JSAtom name_atom = JS_ATOM_NULL;
|
||||||
|
if (f->name != JS_ATOM_NULL) name_atom = f->name;
|
||||||
|
else if (f->kind == JS_FUNC_KIND_BYTECODE && f->u.func.function_bytecode) name_atom = f->u.func.function_bytecode->func_name;
|
||||||
|
|
||||||
|
atom_to_buf(js, name_atom, dbg->name, sizeof(dbg->name), "<anonymous>");
|
||||||
|
|
||||||
|
if (f->kind == JS_FUNC_KIND_BYTECODE) {
|
||||||
|
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||||
|
atom_to_buf(js, b->debug.filename, dbg->filename, sizeof(dbg->filename), "unknown");
|
||||||
|
dbg->what = "JS";
|
||||||
|
dbg->closure_n = b->closure_var_count;
|
||||||
|
dbg->param_n = b->arg_count;
|
||||||
|
dbg->vararg = 1;
|
||||||
|
dbg->source = b->debug.source;
|
||||||
|
dbg->srclen = b->debug.source_len;
|
||||||
|
dbg->line = 0; /* see below */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->kind == JS_FUNC_KIND_C || f->kind == JS_FUNC_KIND_C_DATA) {
|
||||||
|
strncpy(dbg->filename, "<native C>", sizeof(dbg->filename));
|
||||||
|
dbg->filename[sizeof(dbg->filename) - 1] = 0;
|
||||||
|
dbg->what = "C";
|
||||||
|
dbg->param_n = f->length;
|
||||||
|
dbg->vararg = 1;
|
||||||
|
dbg->line = 0;
|
||||||
|
dbg->source = (const uint8_t *)CSTR;
|
||||||
|
dbg->srclen = STRLEN(CSTR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void js_debug_sethook(JSContext *ctx, js_hook hook, int type, void *user)
|
void js_debug_sethook(JSContext *ctx, js_hook hook, int type, void *user)
|
||||||
|
|||||||
@@ -912,21 +912,19 @@ void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_op
|
|||||||
JSValueConst val, const JSPrintValueOptions *options);
|
JSValueConst val, const JSPrintValueOptions *options);
|
||||||
|
|
||||||
typedef struct js_debug {
|
typedef struct js_debug {
|
||||||
const char *name; // nameof function
|
char name[64];
|
||||||
const char *what;
|
char filename[96];
|
||||||
const char *source; // source code of function
|
int unique;
|
||||||
size_t srclen;
|
int line;
|
||||||
const char *filename; // name of file function is in
|
|
||||||
int nparams;
|
|
||||||
int vararg;
|
|
||||||
int line; // line the function is on
|
|
||||||
int param_n;
|
int param_n;
|
||||||
int closure_n;
|
int closure_n;
|
||||||
uint32_t unique; // a unique identifier for this function
|
int vararg;
|
||||||
|
const char *what;
|
||||||
|
const uint8_t *source;
|
||||||
|
int srclen;
|
||||||
} js_debug;
|
} js_debug;
|
||||||
|
|
||||||
void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg);
|
void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg);
|
||||||
void free_js_debug_info(JSContext *js, js_debug *dbg);
|
|
||||||
|
|
||||||
typedef void (*js_hook)(JSContext*, int type, js_debug *dbg, void *user);
|
typedef void (*js_hook)(JSContext*, int type, js_debug *dbg, void *user);
|
||||||
#define JS_HOOK_CALL 1
|
#define JS_HOOK_CALL 1
|
||||||
|
|||||||
Reference in New Issue
Block a user