initial attempt change functions to intrinsic type

This commit is contained in:
2026-01-24 08:57:20 -06:00
parent d8b13548d2
commit 20f10ab887
3 changed files with 427 additions and 153 deletions

View File

@@ -162,6 +162,10 @@ globalThis.log = function(name, args) {
}
}
log.console(
'hello'
)
function disrupt(err)
{
if (is_function(err.toString)) {

View File

@@ -367,6 +367,7 @@ typedef enum {
JS_GC_OBJ_TYPE_VAR_REF,
JS_GC_OBJ_TYPE_JS_CONTEXT,
JS_GC_OBJ_TYPE_ARRAY,
JS_GC_OBJ_TYPE_FUNCTION,
} JSGCObjectTypeEnum;
/* header for GC objects. GC objects are C data structures with a
@@ -679,11 +680,37 @@ typedef struct JSRecord {
} JSRecord;
typedef struct JSFunction {
typedef enum {
JS_FUNC_KIND_C,
JS_FUNC_KIND_BYTECODE,
JS_FUNC_KIND_BOUND,
JS_FUNC_KIND_C_DATA,
} JSFunctionKind;
typedef struct JSFunction {
JSGCObjectHeader header; /* must come first */
JSAtom name;
uint8_t length;
uint8_t kind;
uint8_t free_mark : 1;
union {
struct {
JSContext *realm;
JSCFunctionType c_function;
uint8_t cproto;
int16_t magic;
} cfunc;
struct {
struct JSFunctionBytecode *function_bytecode;
JSVarRef **var_refs;
} func;
struct JSBoundFunction *bound_function;
struct JSCFunctionDataRecord *c_function_data_record;
} u;
} JSFunction;
#define JS_VALUE_GET_ARRAY(v) ((JSArray *)JS_VALUE_GET_PTR(v))
#define JS_VALUE_GET_FUNCTION(v) ((JSFunction *)JS_VALUE_GET_PTR(v))
typedef struct JSClosureVar {
uint8_t is_local : 1;
@@ -1021,6 +1048,16 @@ 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);
static void mark_function_children(JSRuntime *rt, JSFunction *func, JS_MarkFunc *mark_func);
static void mark_function_children_decref(JSRuntime *rt, JSFunction *func);
#ifdef RC_TRACE
static void gc_decref_child_dbg(JSRuntime *rt, JSGCObjectHeader *parent,
const char *edge, JSAtom atom, int prop_index,
JSGCObjectHeader *child,
const char *file, int line);
#endif
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val);
@@ -4907,25 +4944,19 @@ static BOOL js_class_has_bytecode(JSClassID class_id)
/* Check if a value is a function that uses proxy-call syntax (fn.a -> fn("a")) */
static BOOL js_is_proxy_callable(JSValueConst v)
{
JSObject *p;
if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
return FALSE;
p = JS_VALUE_GET_OBJ(v);
return p->class_id == JS_CLASS_BYTECODE_FUNCTION ||
p->class_id == JS_CLASS_C_FUNCTION ||
p->class_id == JS_CLASS_C_FUNCTION_DATA;
return JS_VALUE_GET_TAG(v) == JS_TAG_FUNCTION;
}
/* return NULL without exception if not a function or no bytecode */
static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
{
JSObject *p;
if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
JSFunction *f;
if (JS_VALUE_GET_TAG(val) != JS_TAG_FUNCTION)
return NULL;
p = JS_VALUE_GET_OBJ(val);
if (!js_class_has_bytecode(p->class_id))
f = JS_VALUE_GET_FUNCTION(val);
if (f->kind != JS_FUNC_KIND_BYTECODE)
return NULL;
return p->u.func.function_bytecode;
return f->u.func.function_bytecode;
}
static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
@@ -4963,18 +4994,20 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
JSValueConst proto_val)
{
JSValue func_obj;
JSObject *p;
JSFunction *f;
JSAtom name_atom;
func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
(void)proto_val; /* unused - intrinsic functions have no prototype */
func_obj = js_new_function(ctx, JS_FUNC_KIND_C);
if (JS_IsException(func_obj))
return func_obj;
p = JS_VALUE_GET_OBJ(func_obj);
p->u.cfunc.realm = JS_DupContext(ctx);
p->u.cfunc.c_function.generic = func;
p->u.cfunc.length = length;
p->u.cfunc.cproto = cproto;
p->u.cfunc.magic = magic;
f = JS_VALUE_GET_FUNCTION(func_obj);
f->u.cfunc.realm = JS_DupContext(ctx);
f->u.cfunc.c_function.generic = func;
f->u.cfunc.cproto = cproto;
f->u.cfunc.magic = magic;
f->length = length;
if (!name)
name = "";
name_atom = JS_NewAtom(ctx, name);
@@ -4982,8 +5015,7 @@ static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
JS_FreeValue(ctx, func_obj);
return JS_EXCEPTION;
}
js_function_set_properties(ctx, func_obj, name_atom, length);
JS_FreeAtom(ctx, name_atom);
f->name = name_atom;
return func_obj;
}
@@ -5034,10 +5066,13 @@ static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_val,
int argc, JSValueConst *argv, int flags)
{
JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
JSFunction *f = JS_VALUE_GET_FUNCTION(func_obj);
JSCFunctionDataRecord *s = f->u.c_function_data_record;
JSValueConst *arg_buf;
int i;
(void)flags; /* unused */
/* XXX: could add the function on the stack for debug */
if (unlikely(argc < s->length)) {
arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
@@ -5058,10 +5093,10 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
{
JSCFunctionDataRecord *s;
JSValue func_obj;
JSFunction *f;
int i;
func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
JS_CLASS_C_FUNCTION_DATA);
func_obj = js_new_function(ctx, JS_FUNC_KIND_C_DATA);
if (JS_IsException(func_obj))
return func_obj;
s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
@@ -5075,9 +5110,10 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
s->magic = magic;
for(i = 0; i < data_len; i++)
s->data[i] = JS_DupValue(ctx, data[i]);
JS_SetOpaque(func_obj, s);
js_function_set_properties(ctx, func_obj,
JS_ATOM_empty_string, length);
f = JS_VALUE_GET_FUNCTION(func_obj);
f->u.c_function_data_record = s;
f->length = length;
f->name = JS_ATOM_empty_string;
return func_obj;
}
@@ -5258,6 +5294,187 @@ static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
mark_func(rt, &p->u.cfunc.realm->header);
}
/* Allocate intrinsic function (JS_TAG_FUNCTION) */
static JSValue js_new_function(JSContext *ctx, JSFunctionKind kind)
{
JSRuntime *rt = ctx->rt;
JSFunction *func = js_mallocz(ctx, sizeof(JSFunction));
if (!func)
return JS_EXCEPTION;
func->header.ref_count = 1;
func->kind = kind;
func->name = JS_ATOM_NULL;
func->length = 0;
func->free_mark = 0;
add_gc_object(rt, &func->header, JS_GC_OBJ_TYPE_FUNCTION);
return JS_MKPTR(JS_TAG_FUNCTION, func);
}
/* Free intrinsic function (JS_TAG_FUNCTION) */
static void free_function(JSRuntime *rt, JSFunction *func)
{
assert(func->header.gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION);
func->free_mark = 1; /* used to tell the function is invalid when
freeing cycles */
JS_FreeAtomRT(rt, func->name);
switch (func->kind) {
case JS_FUNC_KIND_C:
if (func->u.cfunc.realm)
JS_FreeContext(func->u.cfunc.realm);
break;
case JS_FUNC_KIND_BYTECODE:
if (func->u.func.function_bytecode) {
JSFunctionBytecode *b = func->u.func.function_bytecode;
JSVarRef **var_refs = func->u.func.var_refs;
if (var_refs) {
for (int 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));
}
break;
case JS_FUNC_KIND_BOUND:
if (func->u.bound_function) {
JSBoundFunction *bf = func->u.bound_function;
JS_FreeValueRT(rt, bf->func_obj);
JS_FreeValueRT(rt, bf->this_val);
for (int i = 0; i < bf->argc; i++) {
JS_FreeValueRT(rt, bf->argv[i]);
}
js_free_rt(rt, bf);
}
break;
case JS_FUNC_KIND_C_DATA:
if (func->u.c_function_data_record) {
JSCFunctionDataRecord *s = func->u.c_function_data_record;
for (int i = 0; i < s->data_len; i++) {
JS_FreeValueRT(rt, s->data[i]);
}
js_free_rt(rt, s);
}
break;
default:
break;
}
func->u.c_function_data_record = NULL;
func->length = 0;
func->name = JS_ATOM_NULL;
remove_gc_object(&func->header);
if (func->header.ref_count == 0)
js_free_rt(rt, func);
else
list_add_tail(&func->header.link, &rt->gc_zero_ref_count_list);
}
static void mark_function_children(JSRuntime *rt, JSFunction *func,
JS_MarkFunc *mark_func)
{
switch (func->kind) {
case JS_FUNC_KIND_C:
if (func->u.cfunc.realm)
mark_func(rt, &func->u.cfunc.realm->header);
break;
case JS_FUNC_KIND_BYTECODE:
if (func->u.func.function_bytecode) {
JSFunctionBytecode *b = func->u.func.function_bytecode;
if (func->u.func.var_refs) {
for (int i = 0; i < b->closure_var_count; i++) {
JSVarRef *var_ref = func->u.func.var_refs[i];
if (var_ref) {
mark_func(rt, &var_ref->header);
}
}
}
JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
}
break;
case JS_FUNC_KIND_BOUND:
if (func->u.bound_function) {
JSBoundFunction *bf = func->u.bound_function;
JS_MarkValue(rt, bf->func_obj, mark_func);
JS_MarkValue(rt, bf->this_val, mark_func);
for (int i = 0; i < bf->argc; i++) {
JS_MarkValue(rt, bf->argv[i], mark_func);
}
}
break;
case JS_FUNC_KIND_C_DATA:
if (func->u.c_function_data_record) {
JSCFunctionDataRecord *s = func->u.c_function_data_record;
for (int i = 0; i < s->data_len; i++) {
JS_MarkValue(rt, s->data[i], mark_func);
}
}
break;
default:
break;
}
}
static void mark_function_children_decref(JSRuntime *rt, JSFunction *func)
{
switch (func->kind) {
case JS_FUNC_KIND_C:
if (func->u.cfunc.realm) {
#ifdef RC_TRACE
gc_decref_child_dbg(rt, &func->header, "func.realm", 0, -1,
&func->u.cfunc.realm->header,
__FILE__, __LINE__);
#else
gc_decref_child(rt, &func->u.cfunc.realm->header);
#endif
}
break;
case JS_FUNC_KIND_BYTECODE:
if (func->u.func.function_bytecode) {
JSFunctionBytecode *b = func->u.func.function_bytecode;
if (func->u.func.var_refs) {
for (int i = 0; i < b->closure_var_count; i++) {
JSVarRef *var_ref = func->u.func.var_refs[i];
if (var_ref) {
#ifdef RC_TRACE
gc_decref_child_dbg(rt, &func->header, "func.var_ref",
0, i, &var_ref->header,
__FILE__, __LINE__);
#else
gc_decref_child(rt, &var_ref->header);
#endif
}
}
}
JS_MarkValueEdge(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), &func->header,
"func.bytecode");
}
break;
case JS_FUNC_KIND_BOUND:
if (func->u.bound_function) {
JSBoundFunction *bf = func->u.bound_function;
JS_MarkValueEdge(rt, bf->func_obj, &func->header, "func.bound.func_obj");
JS_MarkValueEdge(rt, bf->this_val, &func->header, "func.bound.this_val");
for (int i = 0; i < bf->argc; i++) {
JS_MarkValueEdge(rt, bf->argv[i], &func->header, "func.bound.argv");
}
}
break;
case JS_FUNC_KIND_C_DATA:
if (func->u.c_function_data_record) {
JSCFunctionDataRecord *s = func->u.c_function_data_record;
for (int i = 0; i < s->data_len; i++) {
JS_MarkValueEdge(rt, s->data[i], &func->header, "func.cdata");
}
}
break;
default:
break;
}
}
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
{
JSObject *p = JS_VALUE_GET_OBJ(val);
@@ -5396,6 +5613,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
case JS_GC_OBJ_TYPE_ARRAY:
free_array(rt, (JSArray *)gp);
break;
case JS_GC_OBJ_TYPE_FUNCTION:
free_function(rt, (JSFunction *)gp);
break;
default:
abort();
}
@@ -5461,6 +5681,7 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
case JS_TAG_ARRAY:
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
case JS_TAG_FUNCTION:
{
JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
@@ -5511,6 +5732,7 @@ void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
case JS_TAG_ARRAY:
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
case JS_TAG_FUNCTION:
mark_func(rt, JS_VALUE_GET_PTR(val));
break;
default:
@@ -5580,6 +5802,12 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
mark_func(rt, &b->realm->header);
}
break;
case JS_GC_OBJ_TYPE_FUNCTION:
{
JSFunction *func = (JSFunction *)gp;
mark_function_children(rt, func, mark_func);
}
break;
case JS_GC_OBJ_TYPE_VAR_REF:
{
JSVarRef *var_ref = (JSVarRef *)gp;
@@ -5690,6 +5918,7 @@ static inline void JS_MarkValueEdgeEx(JSRuntime *rt, JSValueConst val,
case JS_TAG_ARRAY:
case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
case JS_TAG_FUNCTION:
{
JSGCObjectHeader *child = JS_VALUE_GET_PTR(val);
#ifdef RC_TRACE
@@ -5808,6 +6037,12 @@ static void mark_children_decref(JSRuntime *rt, JSGCObjectHeader *gp)
}
}
break;
case JS_GC_OBJ_TYPE_FUNCTION:
{
JSFunction *func = (JSFunction *)gp;
mark_function_children_decref(rt, func);
}
break;
case JS_GC_OBJ_TYPE_VAR_REF:
{
JSVarRef *var_ref = (JSVarRef *)gp;
@@ -5935,6 +6170,7 @@ static void gc_free_cycles(JSRuntime *rt)
case JS_GC_OBJ_TYPE_JS_OBJECT:
case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
case JS_GC_OBJ_TYPE_ARRAY:
case JS_GC_OBJ_TYPE_FUNCTION:
#ifdef DUMP_GC_FREE
if (!header_done) {
printf("Freeing cycles:\n");
@@ -5957,7 +6193,8 @@ static void gc_free_cycles(JSRuntime *rt)
p = list_entry(el, JSGCObjectHeader, link);
assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
p->gc_obj_type == JS_GC_OBJ_TYPE_ARRAY);
p->gc_obj_type == JS_GC_OBJ_TYPE_ARRAY ||
p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION);
js_free_rt(rt, p);
}
@@ -6612,13 +6849,14 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
dbuf_printf(&dbuf, " at %s", str1);
JS_FreeCString(ctx, func_name_str);
p = JS_VALUE_GET_OBJ(sf->cur_func);
if (js_class_has_bytecode(p->class_id)) {
if (JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_FUNCTION) {
JSFunction *fn = JS_VALUE_GET_FUNCTION(sf->cur_func);
if (fn->kind == JS_FUNC_KIND_BYTECODE) {
JSFunctionBytecode *b;
const char *atom_str;
int line_num1, col_num1;
b = p->u.func.function_bytecode;
b = fn->u.func.function_bytecode;
if (b->has_debug) {
line_num1 = find_line_num(ctx, b,
sf->cur_pc - b->byte_code_buf - 1, &col_num1);
@@ -6633,6 +6871,9 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
} else {
dbuf_printf(&dbuf, " (native)");
}
} else {
dbuf_printf(&dbuf, " (native)");
}
dbuf_putc(&dbuf, '\n');
}
dbuf_putc(&dbuf, '\0');
@@ -7953,26 +8194,19 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
{
JSObject *p;
if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
return FALSE;
p = JS_VALUE_GET_OBJ(val);
switch(p->class_id) {
case JS_CLASS_BYTECODE_FUNCTION:
return TRUE;
default:
return (ctx->rt->class_array[p->class_id].call != NULL);
}
(void)ctx; /* unused */
return JS_VALUE_GET_TAG(val) == JS_TAG_FUNCTION;
}
BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
{
JSObject *p;
if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
JSFunction *f;
(void)ctx; /* unused */
if (JS_VALUE_GET_TAG(val) != JS_TAG_FUNCTION)
return FALSE;
p = JS_VALUE_GET_OBJ(val);
if (p->class_id == JS_CLASS_C_FUNCTION)
return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
f = JS_VALUE_GET_FUNCTION(val);
if (f->kind == JS_FUNC_KIND_C)
return (f->u.cfunc.c_function.generic == func && f->u.cfunc.magic == magic);
else
return FALSE;
}
@@ -9276,6 +9510,23 @@ static void js_print_value(JSPrintValueState *s, JSValueConst val)
js_putc(s, ']');
}
break;
case JS_TAG_FUNCTION:
{
JSFunction *f = JS_VALUE_GET_FUNCTION(val);
js_puts(s, "[Function");
if (f->name != JS_ATOM_NULL) {
js_putc(s, ' ');
js_print_atom(s, f->name);
} else if (f->kind == JS_FUNC_KIND_BYTECODE && f->u.func.function_bytecode) {
JSAtom name = f->u.func.function_bytecode->func_name;
if (name != JS_ATOM_NULL) {
js_putc(s, ' ');
js_print_atom(s, name);
}
}
js_putc(s, ']');
}
break;
case JS_TAG_OBJECT:
{
JSObject *p = JS_VALUE_GET_OBJ(val);
@@ -10085,18 +10336,18 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
JSVarRef **cur_var_refs,
JSStackFrame *sf)
{
JSObject *p;
JSFunction *f;
JSVarRef **var_refs;
int i;
p = JS_VALUE_GET_OBJ(func_obj);
p->u.func.function_bytecode = b;
p->u.func.var_refs = NULL;
f = JS_VALUE_GET_FUNCTION(func_obj);
f->u.func.function_bytecode = b;
f->u.func.var_refs = NULL;
if (b->closure_var_count) {
var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
if (!var_refs)
goto fail;
p->u.func.var_refs = var_refs;
f->u.func.var_refs = var_refs;
for(i = 0; i < b->closure_var_count; i++) {
JSClosureVar *cv = &b->closure_var[i];
JSVarRef *var_ref;
@@ -10125,10 +10376,11 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
{
JSFunctionBytecode *b;
JSValue func_obj;
JSFunction *f;
JSAtom name_atom;
b = JS_VALUE_GET_PTR(bfunc);
func_obj = JS_NewObjectClass(ctx, JS_CLASS_BYTECODE_FUNCTION);
func_obj = js_new_function(ctx, JS_FUNC_KIND_BYTECODE);
if (JS_IsException(func_obj)) {
JS_FreeValue(ctx, bfunc);
return JS_EXCEPTION;
@@ -10138,11 +10390,12 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
/* bfunc has been freed */
goto fail;
}
f = JS_VALUE_GET_FUNCTION(func_obj);
name_atom = b->func_name;
if (name_atom == JS_ATOM_NULL)
name_atom = JS_ATOM_empty_string;
js_function_set_properties(ctx, func_obj, name_atom,
b->defined_arg_count);
f->name = JS_DupAtom(ctx, name_atom);
f->length = b->defined_arg_count;
return func_obj;
fail:
/* bfunc is freed when func_obj is freed */
@@ -10194,16 +10447,17 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
{
JSRuntime *rt = ctx->rt;
JSCFunctionType func;
JSObject *p;
JSFunction *f;
JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
JSValue ret_val;
JSValueConst *arg_buf;
int arg_count, i;
JSCFunctionEnum cproto;
p = JS_VALUE_GET_OBJ(func_obj);
cproto = p->u.cfunc.cproto;
arg_count = p->u.cfunc.length;
(void)flags; /* unused */
f = JS_VALUE_GET_FUNCTION(func_obj);
cproto = f->u.cfunc.cproto;
arg_count = f->length;
/* better to always check stack overflow */
if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
@@ -10212,7 +10466,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
prev_sf = rt->current_stack_frame;
sf->prev_frame = prev_sf;
rt->current_stack_frame = sf;
ctx = p->u.cfunc.realm; /* change the current realm */
ctx = f->u.cfunc.realm; /* change the current realm */
sf->js_mode = 0;
sf->cur_func = (JSValue)func_obj;
sf->arg_count = argc;
@@ -10229,7 +10483,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
}
sf->arg_buf = (JSValue*)arg_buf;
func = p->u.cfunc.c_function;
func = f->u.cfunc.c_function;
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_CALL)) {
js_debug dbg = {0};
@@ -10244,7 +10498,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
break;
case JS_CFUNC_generic_magic:
ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
p->u.cfunc.magic);
f->u.cfunc.magic);
break;
case JS_CFUNC_f_f:
{
@@ -10292,13 +10546,15 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
JSValueConst this_obj,
int argc, JSValueConst *argv, int flags)
{
JSObject *p;
JSFunction *f;
JSBoundFunction *bf;
JSValueConst *arg_buf;
int arg_count, i;
p = JS_VALUE_GET_OBJ(func_obj);
bf = p->u.bound_function;
(void)this_obj; /* unused - bound function uses bf->this_val */
(void)flags; /* unused */
f = JS_VALUE_GET_FUNCTION(func_obj);
bf = f->u.bound_function;
arg_count = bf->argc + argc;
if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
return JS_ThrowStackOverflow(ctx);
@@ -10400,14 +10656,14 @@ static struct VMFrame *vm_push_frame(JSContext *ctx,
const uint8_t *ret_pc, int ret_sp_offset,
int call_argc, int call_has_this)
{
JSObject *p;
JSFunction *f;
JSFunctionBytecode *b;
struct VMFrame *frame;
int total_slots, i, arg_allocated_size;
JSValue *stack_base, *arg_buf, *var_buf;
p = JS_VALUE_GET_OBJ(func_obj);
b = p->u.func.function_bytecode;
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) {
@@ -10467,7 +10723,7 @@ static struct VMFrame *vm_push_frame(JSContext *ctx,
frame->ctx = b->realm;
frame->pc = b->byte_code_buf;
frame->js_mode = b->js_mode;
frame->var_refs = p->u.func.var_refs;
frame->var_refs = f->u.func.var_refs;
init_list_head(&frame->var_ref_list);
/* Continuation info for return */
@@ -10612,7 +10868,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
{
JSRuntime *rt = caller_ctx->rt;
JSContext *ctx;
JSObject *p;
JSFunction *f;
JSFunctionBytecode *b;
JSStackFrame sf_s, *sf = &sf_s;
const uint8_t *pc;
@@ -10652,21 +10908,27 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
if (js_poll_interrupts(caller_ctx))
return JS_EXCEPTION;
if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
goto 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) {
if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_FUNCTION)) {
not_a_function:
return JS_ThrowTypeError(caller_ctx, "not a function");
}
return call_func(caller_ctx, func_obj, this_obj, argc,
f = JS_VALUE_GET_FUNCTION(func_obj);
switch (f->kind) {
case JS_FUNC_KIND_C:
return js_call_c_function(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv, flags);
case JS_FUNC_KIND_BOUND:
return js_call_bound_function(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv, flags);
case JS_FUNC_KIND_C_DATA:
return js_c_function_data_call(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv, flags);
case JS_FUNC_KIND_BYTECODE:
break; /* continue to bytecode execution below */
default:
goto not_a_function;
}
b = p->u.func.function_bytecode;
b = f->u.func.function_bytecode;
#ifdef DUMP_PROFILE
/* Increment function entry count */
@@ -10696,7 +10958,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sf->arg_count = argc;
sf->cur_func = (JSValue)func_obj;
init_list_head(&sf->var_ref_list);
var_refs = p->u.func.var_refs;
var_refs = f->u.func.var_refs;
local_buf = alloca(alloca_size);
if (unlikely(arg_allocated_size)) {
@@ -13044,29 +13306,30 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
NULL in case of exception (case of revoked proxy only) */
static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
{
JSObject *p;
JSFunction *f;
JSContext *realm;
if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_FUNCTION)
return ctx;
p = JS_VALUE_GET_OBJ(func_obj);
switch(p->class_id) {
case JS_CLASS_C_FUNCTION:
realm = p->u.cfunc.realm;
f = JS_VALUE_GET_FUNCTION(func_obj);
switch(f->kind) {
case JS_FUNC_KIND_C:
realm = f->u.cfunc.realm;
break;
case JS_CLASS_BYTECODE_FUNCTION:
case JS_FUNC_KIND_BYTECODE:
{
JSFunctionBytecode *b;
b = p->u.func.function_bytecode;
b = f->u.func.function_bytecode;
realm = b->realm;
}
break;
case JS_CLASS_BOUND_FUNCTION:
case JS_FUNC_KIND_BOUND:
{
JSBoundFunction *bf = p->u.bound_function;
JSBoundFunction *bf = f->u.bound_function;
realm = JS_GetFunctionRealm(ctx, bf->func_obj);
}
break;
case JS_FUNC_KIND_C_DATA:
default:
realm = ctx;
break;
@@ -22859,14 +23122,14 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
eval_type = flags & JS_EVAL_TYPE_MASK;
if (eval_type == JS_EVAL_TYPE_DIRECT) {
JSObject *p;
JSFunction *fn;
sf = ctx->rt->current_stack_frame;
assert(sf != NULL);
assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
p = JS_VALUE_GET_OBJ(sf->cur_func);
assert(js_class_has_bytecode(p->class_id));
b = p->u.func.function_bytecode;
var_refs = p->u.func.var_refs;
assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_FUNCTION);
fn = JS_VALUE_GET_FUNCTION(sf->cur_func);
assert(fn->kind == JS_FUNC_KIND_BYTECODE);
b = fn->u.func.function_bytecode;
var_refs = fn->u.func.var_refs;
js_mode = b->js_mode;
} else {
sf = NULL;
@@ -27297,9 +27560,9 @@ array_fail:
/* Handle function - return source or native stub */
if (JS_IsFunction(ctx, arg)) {
JSObject *p = JS_VALUE_GET_OBJ(arg);
if (js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b = p->u.func.function_bytecode;
JSFunction *fn = JS_VALUE_GET_FUNCTION(arg);
if (fn->kind == JS_FUNC_KIND_BYTECODE) {
JSFunctionBytecode *b = fn->u.func.function_bytecode;
if (b->has_debug && b->debug.source)
return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
}
@@ -27309,12 +27572,15 @@ array_fail:
const char *name = "";
const char *name_cstr = NULL;
JSObject *fp = JS_VALUE_GET_OBJ(arg);
if (js_class_has_bytecode(fp->class_id)) {
JSFunctionBytecode *fb = fp->u.func.function_bytecode;
if (fn->kind == JS_FUNC_KIND_BYTECODE) {
JSFunctionBytecode *fb = fn->u.func.function_bytecode;
name_cstr = JS_AtomToCString(ctx, fb->func_name);
if (name_cstr)
name = name_cstr;
} else if (fn->name != JS_ATOM_NULL) {
name_cstr = JS_AtomToCString(ctx, fn->name);
if (name_cstr)
name = name_cstr;
}
size_t plen = strlen(pref);
@@ -30166,17 +30432,8 @@ static JSValue js_cell_length(JSContext *ctx, JSValueConst this_val,
/* Functions return arity (accessed directly, not via properties) */
if (JS_IsFunction(ctx, val)) {
JSObject *p = JS_VALUE_GET_OBJ(val);
switch (p->class_id) {
case JS_CLASS_BYTECODE_FUNCTION:
return JS_NewInt32(ctx, p->u.func.function_bytecode->defined_arg_count);
case JS_CLASS_C_FUNCTION:
return JS_NewInt32(ctx, p->u.cfunc.length);
case JS_CLASS_C_FUNCTION_DATA:
return JS_NewInt32(ctx, p->u.c_function_data_record->length);
default:
return JS_NewInt32(ctx, 0);
}
JSFunction *f = JS_VALUE_GET_FUNCTION(val);
return JS_NewInt32(ctx, f->length);
}
int tag = JS_VALUE_GET_TAG(val);
@@ -30667,10 +30924,15 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
{
memset(dbg, 0, sizeof(*dbg));
if (!JS_IsObject(fn)) return;
JSObject *p = JS_VALUE_GET_OBJ(fn);
if (!JS_IsFunction(js, fn)) return;
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
const char *fn_name = get_prop_string(js, fn, JS_ATOM_name);
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 (!fn_name)
dbg->name = js_strdup(js, "<anonymous>");
@@ -30682,11 +30944,11 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
JS_FreeCString(js,fn_name);
}
dbg->unique = (int)p;
dbg->unique = (int)(uintptr_t)f;
switch(p->class_id) {
case JS_CLASS_BYTECODE_FUNCTION: {
JSFunctionBytecode *b = p->u.func.function_bytecode;
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)
@@ -30709,15 +30971,18 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
dbg->srclen = b->debug.source_len;
break;
}
case JS_CLASS_C_FUNCTION:
case JS_FUNC_KIND_C:
case JS_FUNC_KIND_C_DATA:
dbg->filename = js_strdup(js, "<native C>");
dbg->what = "C";
dbg->nparams = 0;
dbg->nparams = f->length;
dbg->vararg = 1;
dbg->line = 0;
dbg->source = CSTR;
dbg->srclen = STRLEN(CSTR);
break;
default:
break;
}
}
@@ -30761,7 +31026,7 @@ JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc)
{
JSStackFrame *sf;
const char *func_name_str;
JSObject *p;
JSFunction *f;
JSValue ret = JS_NewArray(ctx);
uint32_t stack_index = 0;
@@ -30778,12 +31043,13 @@ JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc)
JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, func_name_str));
JS_FreeCString(ctx, func_name_str);
p = JS_VALUE_GET_OBJ(sf->cur_func);
if (p && js_class_has_bytecode(p->class_id)) {
if (JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_FUNCTION) {
f = JS_VALUE_GET_FUNCTION(sf->cur_func);
if (f->kind == JS_FUNC_KIND_BYTECODE) {
JSFunctionBytecode *b;
int line_num1;
b = p->u.func.function_bytecode;
b = f->u.func.function_bytecode;
if (b->has_debug) {
const uint8_t *pc = sf != ctx->rt->current_stack_frame || !cur_pc ? sf->cur_pc : cur_pc;
int col_num;
@@ -30795,6 +31061,9 @@ JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc)
} else {
JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, "(native)"));
}
} else {
JS_SetPropertyStr(ctx, current_frame, "name", JS_NewString(ctx, "(native)"));
}
JS_SetPropertyUint32(ctx, ret, id, current_frame);
}
return ret;

View File

@@ -79,6 +79,7 @@ enum {
JS_TAG_STRING = -8,
JS_TAG_STRING_ROPE = -7,
JS_TAG_ARRAY = -6, /* intrinsic array type */
JS_TAG_FUNCTION = -5, /* intrinsic function type */
JS_TAG_MODULE = -3, /* used internally */
JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
JS_TAG_OBJECT = -1,