This commit is contained in:
2025-12-29 01:15:30 -06:00
parent 4f3e2819fe
commit 0720368c48
2 changed files with 133 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ DEF(true, "true")
DEF(if, "if") DEF(if, "if")
DEF(else, "else") DEF(else, "else")
DEF(return, "return") DEF(return, "return")
DEF(go, "go")
DEF(var, "var") DEF(var, "var")
DEF(def, "def") DEF(def, "def")
DEF(this, "this") DEF(this, "this")

View File

@@ -125,8 +125,10 @@ typedef struct JSPropSite {
uint64_t hit_count; /* how many times this prop site was executed */ uint64_t hit_count; /* how many times this prop site was executed */
} JSPropSite; } JSPropSite;
/* Forward declare JSFunctionBytecode for JSProfileSample */ /* Forward declarations */
typedef struct JSFunctionBytecode JSFunctionBytecode; typedef struct JSFunctionBytecode JSFunctionBytecode;
typedef struct JSVarRef JSVarRef;
typedef struct VMFrame VMFrame;
/* Sampling profiler sample */ /* Sampling profiler sample */
typedef struct JSProfileSample { typedef struct JSProfileSample {
@@ -262,6 +264,7 @@ struct JSRuntime {
BOOL in_out_of_memory : 8; BOOL in_out_of_memory : 8;
struct JSStackFrame *current_stack_frame; struct JSStackFrame *current_stack_frame;
struct VMFrame *current_vm_frame; /* for trampoline VM */
JSInterruptHandler *interrupt_handler; JSInterruptHandler *interrupt_handler;
void *interrupt_opaque; void *interrupt_opaque;
@@ -306,6 +309,26 @@ typedef struct JSStackFrame {
int js_mode; /* not supported for C functions */ int js_mode; /* not supported for C functions */
} JSStackFrame; } JSStackFrame;
/* Heap-allocated VM frame for trampoline execution */
struct VMFrame {
struct VMFrame *prev_frame;
struct JSFunctionBytecode *b; /* current function bytecode */
JSContext *ctx; /* execution context / realm */
const uint8_t *pc; /* program counter */
JSValue *sp; /* current stack pointer */
JSValue *stack_base; /* base of operand stack (points into heap) */
JSValue *arg_buf; /* arguments (points into stack_base region) */
JSValue *var_buf; /* local variables (points into stack_base region) */
JSValue cur_func; /* current function object */
JSValue this_obj; /* this binding */
JSValue new_target; /* new.target binding */
struct JSVarRef **var_refs; /* closure variable references */
struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
int arg_count;
int js_mode;
int stack_size_allocated; /* total size of stack_base allocation */
};
typedef enum { typedef enum {
JS_GC_OBJ_TYPE_JS_OBJECT, JS_GC_OBJ_TYPE_JS_OBJECT,
JS_GC_OBJ_TYPE_FUNCTION_BYTECODE, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
@@ -12700,6 +12723,113 @@ static void profile_record_prop_site(JSRuntime *rt, JSFunctionBytecode *b, uint3
} }
#endif #endif
/* VM frame management for trampoline */
static struct VMFrame *vm_push_frame(JSRuntime *rt, JSContext *ctx,
JSValueConst func_obj, JSValueConst this_obj,
JSValueConst new_target,
int argc, JSValue *argv, int flags)
{
JSObject *p;
JSFunctionBytecode *b;
struct VMFrame *frame;
int total_slots, i, arg_allocated_size;
p = JS_VALUE_GET_OBJ(func_obj);
b = p->u.func.function_bytecode;
frame = js_malloc(ctx, sizeof(struct VMFrame));
if (!frame)
return NULL;
/* Calculate space needed: args + vars + stack */
if (argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV)) {
arg_allocated_size = b->arg_count;
} else {
arg_allocated_size = 0;
}
total_slots = arg_allocated_size + b->var_count + b->stack_size;
/* Allocate VM stack space */
frame->stack_base = js_mallocz(ctx, sizeof(JSValue) * total_slots);
if (!frame->stack_base) {
js_free(ctx, frame);
return NULL;
}
frame->stack_size_allocated = total_slots;
/* Set up pointers into stack */
if (arg_allocated_size) {
frame->arg_buf = frame->stack_base;
for (i = 0; i < min_int(argc, b->arg_count); i++)
frame->arg_buf[i] = JS_DupValue(ctx, argv[i]);
for (; i < b->arg_count; i++)
frame->arg_buf[i] = JS_NULL;
frame->arg_count = b->arg_count;
} else {
frame->arg_buf = argv;
frame->arg_count = argc;
}
frame->var_buf = frame->stack_base + arg_allocated_size;
for (i = 0; i < b->var_count; i++)
frame->var_buf[i] = JS_NULL;
frame->sp = frame->var_buf + b->var_count;
/* Initialize frame metadata */
frame->cur_func = JS_DupValue(ctx, func_obj);
frame->this_obj = JS_DupValue(ctx, this_obj);
frame->new_target = JS_DupValue(ctx, new_target);
frame->b = b;
frame->ctx = b->realm;
frame->pc = b->byte_code_buf;
frame->js_mode = b->js_mode;
frame->var_refs = p->u.func.var_refs;
init_list_head(&frame->var_ref_list);
/* Link to previous frame */
frame->prev_frame = rt->current_vm_frame;
rt->current_vm_frame = frame;
return frame;
}
static void vm_pop_frame(JSRuntime *rt, struct VMFrame *frame)
{
int i;
struct list_head *el, *el1;
JSContext *ctx = frame->ctx;
/* Close variable references */
if (!list_empty(&frame->var_ref_list)) {
list_for_each_safe(el, el1, &frame->var_ref_list) {
JSVarRef *var_ref = list_entry(el, JSVarRef, var_ref_link);
var_ref->value = JS_DupValue(ctx, *var_ref->pvalue);
var_ref->pvalue = &var_ref->value;
var_ref->is_detached = TRUE;
list_del(&var_ref->var_ref_link);
}
}
/* Free all values in stack */
for (i = 0; i < frame->stack_size_allocated; i++)
JS_FreeValue(ctx, frame->stack_base[i]);
/* Free frame values */
JS_FreeValue(ctx, frame->cur_func);
JS_FreeValue(ctx, frame->this_obj);
JS_FreeValue(ctx, frame->new_target);
/* Free allocations */
js_free(ctx, frame->stack_base);
/* Update runtime pointer */
rt->current_vm_frame = frame->prev_frame;
js_free(ctx, frame);
}
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JSValueConst this_obj, JSValueConst new_target, JSValueConst this_obj, JSValueConst new_target,
int argc, JSValue *argv, int flags) int argc, JSValue *argv, int flags)
@@ -15349,6 +15479,7 @@ enum {
TOK_IF, TOK_IF,
TOK_ELSE, TOK_ELSE,
TOK_RETURN, TOK_RETURN,
TOK_GO,
TOK_VAR, TOK_VAR,
TOK_DEF, TOK_DEF,
TOK_THIS, TOK_THIS,