tracy
This commit is contained in:
251
source/quickjs.c
251
source/quickjs.c
@@ -378,6 +378,112 @@ struct JSGCObjectHeader {
|
||||
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
|
||||
typedef struct RcEvent {
|
||||
JSGCObjectHeader *ptr;
|
||||
@@ -10210,10 +10316,9 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
||||
func = f->u.cfunc.c_function;
|
||||
|
||||
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);
|
||||
ctx->trace_hook(ctx, JS_HOOK_CALL, &dbg, ctx->trace_data);
|
||||
free_js_debug_info(ctx, &dbg);
|
||||
}
|
||||
|
||||
switch(cproto) {
|
||||
@@ -10269,12 +10374,8 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
||||
|
||||
rt->current_stack_frame = sf->prev_frame;
|
||||
|
||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET)) {
|
||||
js_debug dbg = {0};
|
||||
js_debug_info(ctx, func_obj, &dbg);
|
||||
ctx->trace_hook(ctx, JS_HOOK_RET, &dbg, ctx->trace_data);
|
||||
free_js_debug_info(ctx, &dbg);
|
||||
}
|
||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
||||
ctx->trace_hook(ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
@@ -10464,10 +10565,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
#endif
|
||||
|
||||
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);
|
||||
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))) {
|
||||
@@ -12655,12 +12755,8 @@ CASE(OP_template_concat):
|
||||
}
|
||||
rt->current_stack_frame = sf->prev_frame;
|
||||
|
||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_RET)) {
|
||||
js_debug dbg = {0};
|
||||
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);
|
||||
}
|
||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_RET))
|
||||
caller_ctx->trace_hook(caller_ctx, JS_HOOK_RET, NULL, caller_ctx->trace_data);
|
||||
|
||||
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");
|
||||
|
||||
float f;
|
||||
int tag = JS_VALUE_GET_TAG(arg0);
|
||||
if (tag == JS_TAG_INT) {
|
||||
f = (float)JS_VALUE_GET_INT(arg0);
|
||||
} 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;
|
||||
}
|
||||
double d;
|
||||
if (JS_ToFloat64(ctx, &d, arg0) < 0) return JS_EXCEPTION;
|
||||
f = d;
|
||||
|
||||
if (blob_write_bytes(bd, &f, sizeof(f)) < 0)
|
||||
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 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 (!JS_IsFunction(fn)) return;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
|
||||
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);
|
||||
if (atom == JS_ATOM_NULL) {
|
||||
strncpy(dst, fallback, cap);
|
||||
dst[cap - 1] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fn_name)
|
||||
dbg->name = js_strdup(js, "<anonymous>");
|
||||
else if (fn_name[0] == 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;
|
||||
JS_AtomGetStr(ctx, dst, cap, atom);
|
||||
if (dst[0] == 0) {
|
||||
strncpy(dst, fallback, cap);
|
||||
dst[cap - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
js_free(js, dbg->name);
|
||||
*dbg = (js_debug){0};
|
||||
|
||||
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)
|
||||
|
||||
@@ -912,21 +912,19 @@ void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_op
|
||||
JSValueConst val, const JSPrintValueOptions *options);
|
||||
|
||||
typedef struct js_debug {
|
||||
const char *name; // nameof function
|
||||
const char *what;
|
||||
const char *source; // source code of function
|
||||
size_t srclen;
|
||||
const char *filename; // name of file function is in
|
||||
int nparams;
|
||||
int vararg;
|
||||
int line; // line the function is on
|
||||
char name[64];
|
||||
char filename[96];
|
||||
int unique;
|
||||
int line;
|
||||
int param_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;
|
||||
|
||||
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);
|
||||
#define JS_HOOK_CALL 1
|
||||
|
||||
Reference in New Issue
Block a user