rm old function as object code
This commit is contained in:
489
source/quickjs.c
489
source/quickjs.c
@@ -172,10 +172,6 @@ enum {
|
||||
/* classid tag */ /* union usage | properties */
|
||||
JS_CLASS_OBJECT = 1, /* must be first */
|
||||
JS_CLASS_ERROR,
|
||||
JS_CLASS_C_FUNCTION, /* u.cfunc */
|
||||
JS_CLASS_BYTECODE_FUNCTION, /* u.func */
|
||||
JS_CLASS_BOUND_FUNCTION, /* u.bound_function */
|
||||
JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */
|
||||
JS_CLASS_REGEXP, /* u.regexp */
|
||||
JS_CLASS_FINALIZATION_REGISTRY,
|
||||
JS_CLASS_BLOB, /* u.opaque (blob *) */
|
||||
@@ -933,19 +929,6 @@ struct JSObject {
|
||||
uint32_t objkey_size; /* allocated size (power of 2, 0 if none) */
|
||||
union {
|
||||
void *opaque;
|
||||
struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
|
||||
struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
|
||||
struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
|
||||
struct JSFunctionBytecode *function_bytecode;
|
||||
JSVarRef **var_refs;
|
||||
} func;
|
||||
struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
|
||||
JSContext *realm;
|
||||
JSCFunctionType c_function;
|
||||
uint8_t length;
|
||||
uint8_t cproto;
|
||||
int16_t magic;
|
||||
} cfunc;
|
||||
JSRegExp regexp; /* JS_CLASS_REGEXP: 8/16 bytes */
|
||||
} u;
|
||||
};
|
||||
@@ -1039,14 +1022,6 @@ static void js_dump_value_write(void *opaque, const char *buf, size_t len);
|
||||
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int magic);
|
||||
static void free_array(JSRuntime *rt, JSArray *arr);
|
||||
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
|
||||
static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
|
||||
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
|
||||
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func);
|
||||
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
|
||||
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func);
|
||||
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
|
||||
static JSValue js_new_function(JSContext *ctx, JSFunctionKind kind);
|
||||
static void free_function(JSRuntime *rt, JSFunction *func);
|
||||
@@ -1129,9 +1104,6 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
|
||||
JSValueConst array_arg);
|
||||
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
|
||||
JSValue **arrpp, uint32_t *countp);
|
||||
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
|
||||
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func);
|
||||
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int flags);
|
||||
@@ -1332,10 +1304,6 @@ typedef struct JSClassShortDef {
|
||||
static JSClassShortDef const js_std_class_def[] = {
|
||||
{ JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */
|
||||
{ JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
|
||||
{ JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
|
||||
{ JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
|
||||
{ JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
|
||||
{ JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
|
||||
{ JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */
|
||||
};
|
||||
|
||||
@@ -1419,9 +1387,6 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
|
||||
if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
|
||||
countof(js_std_class_def)) < 0)
|
||||
goto fail;
|
||||
rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
|
||||
rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
|
||||
rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
|
||||
if (init_shape_hash(rt))
|
||||
goto fail;
|
||||
|
||||
@@ -4837,9 +4802,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
|
||||
switch(class_id) {
|
||||
case JS_CLASS_OBJECT:
|
||||
break;
|
||||
case JS_CLASS_C_FUNCTION:
|
||||
p->prop[0].u.value = JS_NULL;
|
||||
break;
|
||||
case JS_CLASS_REGEXP:
|
||||
p->u.regexp.pattern = NULL;
|
||||
p->u.regexp.bytecode = NULL;
|
||||
@@ -4936,9 +4898,13 @@ static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
|
||||
JS_SetPropertyInternal(ctx, func_obj, JS_ATOM_name, JS_AtomToString(ctx, name));
|
||||
}
|
||||
|
||||
static BOOL js_class_has_bytecode(JSClassID class_id)
|
||||
/* Helper to check if a value is a bytecode function */
|
||||
static BOOL js_is_bytecode_function(JSValueConst val)
|
||||
{
|
||||
return class_id == JS_CLASS_BYTECODE_FUNCTION;
|
||||
if (JS_VALUE_GET_TAG(val) != JS_TAG_FUNCTION)
|
||||
return FALSE;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(val);
|
||||
return f->kind == JS_FUNC_KIND_BYTECODE;
|
||||
}
|
||||
|
||||
/* Check if a value is a function that uses proxy-call syntax (fn.a -> fn("a")) */
|
||||
@@ -4977,13 +4943,10 @@ static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
|
||||
static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
|
||||
JSAtom name, int flags, JSValueConst home_obj)
|
||||
{
|
||||
JSValue name_str;
|
||||
|
||||
name_str = js_get_function_name(ctx, name);
|
||||
if (JS_IsException(name_str))
|
||||
return -1;
|
||||
if (JS_SetPropertyInternal(ctx, func_obj, JS_ATOM_name, name_str) < 0)
|
||||
if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_FUNCTION)
|
||||
return -1;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(func_obj);
|
||||
f->name = JS_DupAtom(ctx, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5036,32 +4999,6 @@ typedef struct JSCFunctionDataRecord {
|
||||
JSValue data[0];
|
||||
} JSCFunctionDataRecord;
|
||||
|
||||
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
|
||||
int i;
|
||||
|
||||
if (s) {
|
||||
for(i = 0; i < s->data_len; i++) {
|
||||
JS_FreeValueRT(rt, s->data[i]);
|
||||
}
|
||||
js_free_rt(rt, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func)
|
||||
{
|
||||
JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
|
||||
int i;
|
||||
|
||||
if (s) {
|
||||
for(i = 0; i < s->data_len; i++) {
|
||||
JS_MarkValue(rt, s->data[i], mark_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
|
||||
JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int flags)
|
||||
@@ -5277,23 +5214,6 @@ static int js_intrinsic_array_set(JSContext *ctx, JSArray *arr, uint32_t idx, JS
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
|
||||
if (p->u.cfunc.realm)
|
||||
JS_FreeContext(p->u.cfunc.realm);
|
||||
}
|
||||
|
||||
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
|
||||
if (p->u.cfunc.realm)
|
||||
mark_func(rt, &p->u.cfunc.realm->header);
|
||||
}
|
||||
|
||||
/* Allocate intrinsic function (JS_TAG_FUNCTION) */
|
||||
static JSValue js_new_function(JSContext *ctx, JSFunctionKind kind)
|
||||
{
|
||||
@@ -5475,75 +5395,6 @@ static void mark_function_children_decref(JSRuntime *rt, JSFunction *func)
|
||||
}
|
||||
}
|
||||
|
||||
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
JSFunctionBytecode *b;
|
||||
JSVarRef **var_refs;
|
||||
int i;
|
||||
|
||||
b = p->u.func.function_bytecode;
|
||||
if (b) {
|
||||
var_refs = p->u.func.var_refs;
|
||||
if (var_refs) {
|
||||
for(i = 0; i < b->closure_var_count; i++)
|
||||
free_var_ref(rt, var_refs[i]);
|
||||
js_free_rt(rt, var_refs);
|
||||
}
|
||||
JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
|
||||
}
|
||||
}
|
||||
|
||||
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
JSVarRef **var_refs = p->u.func.var_refs;
|
||||
JSFunctionBytecode *b = p->u.func.function_bytecode;
|
||||
int i;
|
||||
|
||||
if (b) {
|
||||
if (var_refs) {
|
||||
for(i = 0; i < b->closure_var_count; i++) {
|
||||
JSVarRef *var_ref = var_refs[i];
|
||||
if (var_ref) {
|
||||
mark_func(rt, &var_ref->header);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* must mark the function bytecode because template objects may be
|
||||
part of a cycle */
|
||||
JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
|
||||
}
|
||||
}
|
||||
|
||||
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
JSBoundFunction *bf = p->u.bound_function;
|
||||
int i;
|
||||
|
||||
JS_FreeValueRT(rt, bf->func_obj);
|
||||
JS_FreeValueRT(rt, bf->this_val);
|
||||
for(i = 0; i < bf->argc; i++) {
|
||||
JS_FreeValueRT(rt, bf->argv[i]);
|
||||
}
|
||||
js_free_rt(rt, bf);
|
||||
}
|
||||
|
||||
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
|
||||
JS_MarkFunc *mark_func)
|
||||
{
|
||||
JSObject *p = JS_VALUE_GET_OBJ(val);
|
||||
JSBoundFunction *bf = p->u.bound_function;
|
||||
int i;
|
||||
|
||||
JS_MarkValue(rt, bf->func_obj, mark_func);
|
||||
JS_MarkValue(rt, bf->this_val, mark_func);
|
||||
for(i = 0; i < bf->argc; i++)
|
||||
JS_MarkValue(rt, bf->argv[i], mark_func);
|
||||
}
|
||||
|
||||
static void free_object(JSRuntime *rt, JSObject *p)
|
||||
{
|
||||
int i;
|
||||
@@ -5591,7 +5442,6 @@ static void free_object(JSRuntime *rt, JSObject *p)
|
||||
/* fail safe */
|
||||
p->class_id = 0;
|
||||
p->u.opaque = NULL;
|
||||
p->u.func.var_refs = NULL;
|
||||
|
||||
remove_gc_object(&p->header);
|
||||
/* no more weakrefs: free if no strong refs, else queue for zero-ref processing */
|
||||
@@ -6372,55 +6222,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
|
||||
}
|
||||
|
||||
switch(p->class_id) {
|
||||
case JS_CLASS_C_FUNCTION: /* u.cfunc */
|
||||
s->c_func_count++;
|
||||
break;
|
||||
case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
|
||||
{
|
||||
JSFunctionBytecode *b = p->u.func.function_bytecode;
|
||||
JSVarRef **var_refs = p->u.func.var_refs;
|
||||
/* home_object: object will be accounted for in list scan */
|
||||
if (var_refs) {
|
||||
s->memory_used_count++;
|
||||
s->js_func_size += b->closure_var_count * sizeof(*var_refs);
|
||||
for (i = 0; i < b->closure_var_count; i++) {
|
||||
if (var_refs[i]) {
|
||||
double ref_count = var_refs[i]->header.ref_count;
|
||||
s->memory_used_count += 1 / ref_count;
|
||||
s->js_func_size += sizeof(*var_refs[i]) / ref_count;
|
||||
/* handle non object closed values */
|
||||
if (var_refs[i]->pvalue == &var_refs[i]->value) {
|
||||
/* potential multiple count */
|
||||
compute_value_size(var_refs[i]->value, hp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JS_CLASS_BOUND_FUNCTION: /* u.bound_function */
|
||||
{
|
||||
JSBoundFunction *bf = p->u.bound_function;
|
||||
/* func_obj and this_val are objects */
|
||||
for (i = 0; i < bf->argc; i++) {
|
||||
compute_value_size(bf->argv[i], hp);
|
||||
}
|
||||
s->memory_used_count += 1;
|
||||
s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
|
||||
}
|
||||
break;
|
||||
case JS_CLASS_C_FUNCTION_DATA: /* u.c_function_data_record */
|
||||
{
|
||||
JSCFunctionDataRecord *fd = p->u.c_function_data_record;
|
||||
if (fd) {
|
||||
for (i = 0; i < fd->data_len; i++) {
|
||||
compute_value_size(fd->data[i], hp);
|
||||
}
|
||||
s->memory_used_count += 1;
|
||||
s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JS_CLASS_REGEXP: /* u.regexp */
|
||||
compute_jsstring_size(p->u.regexp.pattern, hp);
|
||||
compute_jsstring_size(p->u.regexp.bytecode, hp);
|
||||
@@ -9351,22 +9152,7 @@ static void js_print_object(JSPrintValueState *s, JSObject *p)
|
||||
|
||||
comma_state = 0;
|
||||
is_array = FALSE;
|
||||
if (p->class_id == JS_CLASS_BYTECODE_FUNCTION || rt->class_array[p->class_id].call != NULL) {
|
||||
js_printf(s, "[Function");
|
||||
/* XXX: allow dump without ctx */
|
||||
if (!s->options.raw_dump && s->ctx) {
|
||||
const char *func_name_str;
|
||||
js_putc(s, ' ');
|
||||
func_name_str = get_func_name(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p));
|
||||
if (!func_name_str || func_name_str[0] == '\0')
|
||||
js_puts(s, "(anonymous)");
|
||||
else
|
||||
js_puts(s, func_name_str);
|
||||
JS_FreeCString(s->ctx, func_name_str);
|
||||
}
|
||||
js_printf(s, "]");
|
||||
comma_state = 2;
|
||||
} else if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) {
|
||||
if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) {
|
||||
JSValue str = js_regexp_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL);
|
||||
if (JS_IsException(str))
|
||||
goto default_obj;
|
||||
@@ -9428,22 +9214,6 @@ static void js_print_object(JSPrintValueState *s, JSObject *p)
|
||||
if (j > s->options.max_item_count)
|
||||
js_print_more_items(s, &comma_state, j - s->options.max_item_count);
|
||||
}
|
||||
if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) {
|
||||
JSFunctionBytecode *b = p->u.func.function_bytecode;
|
||||
if (b->closure_var_count) {
|
||||
JSVarRef **var_refs;
|
||||
var_refs = p->u.func.var_refs;
|
||||
|
||||
js_print_comma(s, &comma_state);
|
||||
js_printf(s, "[[Closure]]: [");
|
||||
for(i = 0; i < b->closure_var_count; i++) {
|
||||
if (i != 0)
|
||||
js_printf(s, ", ");
|
||||
js_print_value(s, var_refs[i]->value);
|
||||
}
|
||||
js_printf(s, " ]");
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array) {
|
||||
if (comma_state != 2) {
|
||||
@@ -10649,219 +10419,6 @@ static void profile_record_prop_site(JSRuntime *rt, JSFunctionBytecode *b, uint3
|
||||
}
|
||||
#endif
|
||||
|
||||
/* VM frame management for trampoline - no malloc/free! */
|
||||
static struct VMFrame *vm_push_frame(JSContext *ctx,
|
||||
JSValueConst func_obj, JSValueConst this_obj,
|
||||
int argc, JSValue *argv, int flags,
|
||||
const uint8_t *ret_pc, int ret_sp_offset,
|
||||
int call_argc, int call_has_this)
|
||||
{
|
||||
JSFunction *f;
|
||||
JSFunctionBytecode *b;
|
||||
struct VMFrame *frame;
|
||||
int total_slots, i, arg_allocated_size;
|
||||
JSValue *stack_base, *arg_buf, *var_buf;
|
||||
|
||||
f = JS_VALUE_GET_FUNCTION(func_obj);
|
||||
b = f->u.func.function_bytecode;
|
||||
|
||||
/* Check frame stack capacity */
|
||||
if (ctx->frame_stack_top + 1 >= ctx->frame_stack_capacity) {
|
||||
/* TODO: grow frame stack (for now, fail) */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate space needed: args + vars + operand 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;
|
||||
|
||||
/* Check value stack capacity */
|
||||
if (ctx->value_stack_top + total_slots > ctx->value_stack_capacity) {
|
||||
/* TODO: grow value stack (for now, fail) */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Push frame */
|
||||
ctx->frame_stack_top++;
|
||||
frame = &ctx->frame_stack[ctx->frame_stack_top];
|
||||
|
||||
/* Store offsets (safe with realloc) */
|
||||
frame->value_stack_base = ctx->value_stack_top;
|
||||
frame->stack_size_allocated = total_slots;
|
||||
|
||||
/* Get pointers for initialization (only used locally) */
|
||||
stack_base = &ctx->value_stack[frame->value_stack_base];
|
||||
|
||||
if (arg_allocated_size) {
|
||||
frame->arg_buf_offset = 0;
|
||||
arg_buf = stack_base;
|
||||
for (i = 0; i < min_int(argc, b->arg_count); i++)
|
||||
arg_buf[i] = JS_DupValue(ctx, argv[i]);
|
||||
for (; i < b->arg_count; i++)
|
||||
arg_buf[i] = JS_NULL;
|
||||
frame->arg_count = b->arg_count;
|
||||
} else {
|
||||
frame->arg_buf_offset = -1; /* signal: args are aliased from caller */
|
||||
frame->arg_count = argc;
|
||||
}
|
||||
|
||||
frame->var_buf_offset = arg_allocated_size;
|
||||
var_buf = stack_base + arg_allocated_size;
|
||||
for (i = 0; i < b->var_count; i++)
|
||||
var_buf[i] = JS_NULL;
|
||||
|
||||
frame->sp_offset = arg_allocated_size + b->var_count;
|
||||
|
||||
/* Initialize frame metadata */
|
||||
frame->cur_func = JS_DupValue(ctx, func_obj);
|
||||
frame->this_obj = JS_DupValue(ctx, this_obj);
|
||||
frame->b = b;
|
||||
frame->ctx = b->realm;
|
||||
frame->pc = b->byte_code_buf;
|
||||
frame->js_mode = b->js_mode;
|
||||
frame->var_refs = f->u.func.var_refs;
|
||||
init_list_head(&frame->var_ref_list);
|
||||
|
||||
/* Continuation info for return */
|
||||
frame->ret_pc = ret_pc;
|
||||
frame->ret_sp_offset = ret_sp_offset;
|
||||
frame->call_argc = call_argc;
|
||||
frame->call_has_this = call_has_this;
|
||||
|
||||
/* Bump value stack top */
|
||||
ctx->value_stack_top += total_slots;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
static void vm_pop_frame(JSContext *ctx)
|
||||
{
|
||||
struct VMFrame *frame;
|
||||
int i;
|
||||
struct list_head *el, *el1;
|
||||
JSValue *stack_base;
|
||||
|
||||
if (ctx->frame_stack_top < 0)
|
||||
return;
|
||||
|
||||
frame = &ctx->frame_stack[ctx->frame_stack_top];
|
||||
stack_base = &ctx->value_stack[frame->value_stack_base];
|
||||
|
||||
/* Close variable references */
|
||||
if (!list_empty(&frame->var_ref_list)) {
|
||||
list_for_each_safe(el, el1, &frame->var_ref_list) {
|
||||
struct JSVarRef *var_ref = list_entry(el, struct 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 this frame's value stack region */
|
||||
for (i = 0; i < frame->stack_size_allocated; i++)
|
||||
JS_FreeValue(ctx, stack_base[i]);
|
||||
|
||||
/* Free frame values */
|
||||
JS_FreeValue(ctx, frame->cur_func);
|
||||
JS_FreeValue(ctx, frame->this_obj);
|
||||
|
||||
/* Pop frame and value stack */
|
||||
ctx->value_stack_top -= frame->stack_size_allocated;
|
||||
ctx->frame_stack_top--;
|
||||
}
|
||||
|
||||
/* Helper: get pointer from offset (used in hot path) */
|
||||
static inline JSValue *vm_frame_get_stack_ptr(JSContext *ctx, struct VMFrame *frame, int offset)
|
||||
{
|
||||
return &ctx->value_stack[frame->value_stack_base + offset];
|
||||
}
|
||||
|
||||
/* Helper: get current sp pointer for a frame */
|
||||
static inline JSValue *vm_frame_get_sp(JSContext *ctx, struct VMFrame *frame)
|
||||
{
|
||||
return &ctx->value_stack[frame->value_stack_base + frame->sp_offset];
|
||||
}
|
||||
|
||||
/* Helper: get var_buf pointer for a frame */
|
||||
static inline JSValue *vm_frame_get_var_buf(JSContext *ctx, struct VMFrame *frame)
|
||||
{
|
||||
return &ctx->value_stack[frame->value_stack_base + frame->var_buf_offset];
|
||||
}
|
||||
|
||||
/* Helper: get arg_buf pointer for a frame (or NULL if aliased) */
|
||||
static inline JSValue *vm_frame_get_arg_buf(JSContext *ctx, struct VMFrame *frame)
|
||||
{
|
||||
if (frame->arg_buf_offset < 0)
|
||||
return NULL; /* aliased */
|
||||
return &ctx->value_stack[frame->value_stack_base + frame->arg_buf_offset];
|
||||
}
|
||||
|
||||
/* Trampoline VM dispatcher - runs frames without C recursion */
|
||||
static JSValue JS_CallTrampoline(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
JSValueConst this_obj,
|
||||
int argc, JSValue *argv, int flags)
|
||||
{
|
||||
JSRuntime *rt = caller_ctx->rt;
|
||||
JSObject *p;
|
||||
JSValue ret_val = JS_NULL;
|
||||
struct VMFrame *frame;
|
||||
|
||||
/* Check if function is callable */
|
||||
if (js_poll_interrupts(caller_ctx))
|
||||
return JS_EXCEPTION;
|
||||
if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
|
||||
return JS_ThrowTypeError(caller_ctx, "not a function");
|
||||
|
||||
p = JS_VALUE_GET_OBJ(func_obj);
|
||||
if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
|
||||
JSClassCall *call_func;
|
||||
call_func = rt->class_array[p->class_id].call;
|
||||
if (!call_func)
|
||||
return JS_ThrowTypeError(caller_ctx, "not a function");
|
||||
return call_func(caller_ctx, func_obj, this_obj, argc,
|
||||
(JSValueConst *)argv, flags);
|
||||
}
|
||||
|
||||
/* Push initial frame (entry point, no continuation) */
|
||||
frame = vm_push_frame(caller_ctx, func_obj, this_obj,
|
||||
argc, argv, flags,
|
||||
NULL, 0, 0, 0);
|
||||
if (!frame)
|
||||
return JS_ThrowStackOverflow(caller_ctx);
|
||||
|
||||
/* Trampoline loop - execute frames without C recursion */
|
||||
while (caller_ctx->frame_stack_top >= 0) {
|
||||
/* For now, fall back to old JS_CallInternal for the actual execution */
|
||||
/* This is a stub - we'll implement vm_execute_frame next */
|
||||
/* TODO: call vm_execute_frame(caller_ctx, frame) here */
|
||||
|
||||
/* For now, just return and clean up */
|
||||
vm_pop_frame(caller_ctx);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Execute a single frame (delegates to OLD implementation for now) */
|
||||
static VMExecState vm_execute_frame(JSContext *ctx, struct VMFrame *frame,
|
||||
JSValue *ret_val, VMCallInfo *call_info)
|
||||
{
|
||||
/* TODO: Replace with proper bytecode loop extraction */
|
||||
/* For now, delegate to the old recursive implementation */
|
||||
*ret_val = JS_CallInternal(ctx, frame->cur_func, frame->this_obj,
|
||||
frame->arg_count,
|
||||
vm_frame_get_arg_buf(ctx, frame), 0);
|
||||
if (JS_IsException(*ret_val))
|
||||
return VM_EXEC_EXCEPTION;
|
||||
return VM_EXEC_RETURN;
|
||||
}
|
||||
|
||||
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
JSValueConst this_obj,
|
||||
int argc, JSValue *argv, int flags)
|
||||
@@ -30707,10 +30264,10 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
|
||||
|
||||
ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
|
||||
|
||||
/* function_proto is kept for API compatibility but functions are now intrinsic types */
|
||||
ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
|
||||
JS_CFUNC_generic, 0,
|
||||
ctx->class_proto[JS_CLASS_OBJECT]);
|
||||
ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
|
||||
ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
|
||||
|
||||
for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
|
||||
@@ -31072,10 +30629,10 @@ JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc)
|
||||
JSValue js_debugger_fn_info(JSContext *ctx, JSValue fn)
|
||||
{
|
||||
JSValue ret = JS_NewObject(ctx);
|
||||
JSObject *f = JS_VALUE_GET_OBJ(fn);
|
||||
if (!f || !js_class_has_bytecode(f->class_id))
|
||||
if (!js_is_bytecode_function(fn))
|
||||
goto done;
|
||||
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
char atom_buf[ATOM_GET_STR_BUF_SIZE];
|
||||
const char *str;
|
||||
@@ -31177,10 +30734,10 @@ static const char *opcode_names[] = {
|
||||
|
||||
JSValue js_debugger_fn_bytecode(JSContext *ctx, JSValue fn)
|
||||
{
|
||||
JSObject *f = JS_VALUE_GET_OBJ(fn);
|
||||
if (!f || !js_class_has_bytecode(f->class_id))
|
||||
if (!js_is_bytecode_function(fn))
|
||||
return JS_NULL;
|
||||
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
JSValue ret = JS_NewArray(ctx);
|
||||
|
||||
@@ -31493,8 +31050,8 @@ JSValue js_debugger_local_variables(JSContext *ctx, int stack_index) {
|
||||
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
|
||||
// this val is one frame up
|
||||
if (cur_index == stack_index - 1) {
|
||||
JSObject *f = JS_VALUE_GET_OBJ(sf->cur_func);
|
||||
if (f && js_class_has_bytecode(f->class_id)) {
|
||||
if (js_is_bytecode_function(sf->cur_func)) {
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(sf->cur_func);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
|
||||
JSValue this_obj = sf->var_buf[b->var_count];
|
||||
@@ -31509,9 +31066,9 @@ JSValue js_debugger_local_variables(JSContext *ctx, int stack_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JSObject *f = JS_VALUE_GET_OBJ(sf->cur_func);
|
||||
if (!f || !js_class_has_bytecode(f->class_id))
|
||||
if (!js_is_bytecode_function(sf->cur_func))
|
||||
goto done;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(sf->cur_func);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
|
||||
for (uint32_t i = 0; i < b->arg_count + b->var_count; i++) {
|
||||
@@ -31537,10 +31094,10 @@ done:
|
||||
|
||||
void js_debugger_set_closure_variable(JSContext *ctx, JSValue fn, JSValue var_name, JSValue val)
|
||||
{
|
||||
JSObject *f = JS_VALUE_GET_OBJ(fn);
|
||||
if (!f || !js_class_has_bytecode(f->class_id))
|
||||
if (!js_is_bytecode_function(fn))
|
||||
return;
|
||||
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
const char *name_str = JS_ToCString(ctx, var_name);
|
||||
if (!name_str)
|
||||
@@ -31571,10 +31128,10 @@ void js_debugger_set_closure_variable(JSContext *ctx, JSValue fn, JSValue var_na
|
||||
|
||||
JSValue js_debugger_closure_variables(JSContext *ctx, JSValue fn) {
|
||||
JSValue ret = JS_NewObject(ctx);
|
||||
JSObject *f = JS_VALUE_GET_OBJ(fn);
|
||||
if (!f || !js_class_has_bytecode(f->class_id))
|
||||
if (!js_is_bytecode_function(fn))
|
||||
goto done;
|
||||
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
JSFunctionBytecode *b = f->u.func.function_bytecode;
|
||||
|
||||
for (uint32_t i = 0; i < b->closure_var_count; i++) {
|
||||
|
||||
Reference in New Issue
Block a user