simplify gc model
This commit is contained in:
@@ -442,7 +442,7 @@ JSFrameRegister *alloc_frame_register(JSContext *ctx, int slot_count) {
|
|||||||
if (!frame) return NULL;
|
if (!frame) return NULL;
|
||||||
|
|
||||||
/* cap56 = slot count (used by gc_object_size) */
|
/* cap56 = slot count (used by gc_object_size) */
|
||||||
frame->hdr = objhdr_make(slot_count, OBJ_FRAME, 0, 0, 0, 0);
|
frame->header = objhdr_make(slot_count, OBJ_FRAME, 0, 0, 0, 0);
|
||||||
frame->function = JS_NULL;
|
frame->function = JS_NULL;
|
||||||
frame->caller = JS_NULL;
|
frame->caller = JS_NULL;
|
||||||
frame->address = JS_NewInt32(ctx, 0);
|
frame->address = JS_NewInt32(ctx, 0);
|
||||||
@@ -1695,7 +1695,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
case MACH_INVOKE: {
|
case MACH_INVOKE: {
|
||||||
/* A=frame_slot, B=result_slot */
|
/* A=frame_slot, B=result_slot */
|
||||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||||
int nr = (int)objhdr_cap56(fr->hdr);
|
int nr = (int)objhdr_cap56(fr->header);
|
||||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
||||||
JSValue fn_val = fr->function;
|
JSValue fn_val = fr->function;
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||||
@@ -1746,7 +1746,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
case MACH_GOINVOKE: {
|
case MACH_GOINVOKE: {
|
||||||
/* Async invoke: call and discard result */
|
/* Async invoke: call and discard result */
|
||||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||||
int nr = (int)objhdr_cap56(fr->hdr);
|
int nr = (int)objhdr_cap56(fr->header);
|
||||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
||||||
ctx->reg_current_frame = frame_ref.val;
|
ctx->reg_current_frame = frame_ref.val;
|
||||||
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ void cell_rt_setarg(JSValue frame_val, int64_t idx, JSValue val) {
|
|||||||
|
|
||||||
JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) {
|
JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) {
|
||||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
|
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
|
||||||
int nr_slots = (int)objhdr_cap56(fr->hdr);
|
int nr_slots = (int)objhdr_cap56(fr->header);
|
||||||
int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0;
|
int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0;
|
||||||
|
|
||||||
/* Copy args to C stack */
|
/* Copy args to C stack */
|
||||||
|
|||||||
@@ -361,13 +361,7 @@ struct JSClass {
|
|||||||
#define JS_MODE_BACKTRACE_BARRIER \
|
#define JS_MODE_BACKTRACE_BARRIER \
|
||||||
(1 << 3) /* stop backtrace before this frame */
|
(1 << 3) /* stop backtrace before this frame */
|
||||||
|
|
||||||
typedef struct JSFrameRegister {
|
/* JSFrameRegister is now an alias for JSFrame — see JSFrame definition below */
|
||||||
objhdr_t hdr; // capacity in this is the total number of words of the object, including the 4 words of overhead and all slots
|
|
||||||
JSValue function; // JSFunction, function object being invoked
|
|
||||||
JSValue caller; // JSFrameRegister, the frame that called this one
|
|
||||||
JSValue address; // address of the instruction in the code that should be executed upon return
|
|
||||||
JSValue slots[]; // inline memory. order is [this][input args][closed over vars][non closed over vars][temporaries]
|
|
||||||
} JSFrameRegister; /// extra note: when this frame returns, caller should be set to 0. If caller is found to be 0, then the GC can reduce this frame's slots down to [this][input_args][closed over vars]; if no closed over vars it can be totally removed; may happen naturally in GC since it would have no refs?
|
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
Register-Based VM Data Structures
|
Register-Based VM Data Structures
|
||||||
@@ -823,17 +817,18 @@ typedef struct JSCodeRegister {
|
|||||||
} JSCodeRegister;
|
} JSCodeRegister;
|
||||||
|
|
||||||
|
|
||||||
/* Frame for closures - used by link-time relocation model where closures
|
/* Unified frame struct — used by the register VM and closures.
|
||||||
reference outer frames via (depth, slot) addressing.
|
All fields are JSValues so the GC can scan them uniformly. */
|
||||||
Stores function as JSValue to survive GC movements. */
|
|
||||||
typedef struct JSFrame {
|
typedef struct JSFrame {
|
||||||
objhdr_t header; /* OBJ_FRAME, cap56 = slot count */
|
objhdr_t header; /* OBJ_FRAME, cap56 = slot count */
|
||||||
JSValue function; /* JSValue for GC safety (use JS_VALUE_GET_FUNCTION) */
|
JSValue function; /* JSFunction, function object being invoked */
|
||||||
JSValue caller; /* JSValue for GC safety (unused currently) */
|
JSValue caller; /* JSFrame, the frame that called this one */
|
||||||
uint32_t return_pc;
|
JSValue address; /* return PC stored as JS_NewInt32 */
|
||||||
JSValue slots[]; /* [this][args][captured][locals][temps] */
|
JSValue slots[]; /* [this][args][captured][locals][temps] */
|
||||||
} JSFrame;
|
} JSFrame;
|
||||||
|
|
||||||
|
typedef JSFrame JSFrameRegister;
|
||||||
|
|
||||||
static inline objhdr_t objhdr_set_s (objhdr_t h, bool s) {
|
static inline objhdr_t objhdr_set_s (objhdr_t h, bool s) {
|
||||||
return s ? (h | OBJHDR_S_MASK) : (h & ~OBJHDR_S_MASK);
|
return s ? (h | OBJHDR_S_MASK) : (h & ~OBJHDR_S_MASK);
|
||||||
}
|
}
|
||||||
@@ -903,7 +898,8 @@ typedef struct JSArray {
|
|||||||
JSValue values[]; /* inline flexible array member */
|
JSValue values[]; /* inline flexible array member */
|
||||||
} JSArray;
|
} JSArray;
|
||||||
|
|
||||||
/* JSBlob - binary data per memory.md */
|
/* JSBlob — not allocated on GC heap (blobs use JSRecord + opaque).
|
||||||
|
Struct kept for reference; gc_object_size/gc_scan_object do not handle OBJ_BLOB. */
|
||||||
typedef struct JSBlob {
|
typedef struct JSBlob {
|
||||||
objhdr_t mist_hdr;
|
objhdr_t mist_hdr;
|
||||||
word_t length;
|
word_t length;
|
||||||
@@ -926,7 +922,7 @@ typedef slot JSRecordEntry;
|
|||||||
|
|
||||||
typedef struct JSRecord {
|
typedef struct JSRecord {
|
||||||
objhdr_t mist_hdr;
|
objhdr_t mist_hdr;
|
||||||
struct JSRecord *proto;
|
JSValue proto; /* prototype as JSValue (JS_NULL if none) */
|
||||||
word_t len; /* number of entries */
|
word_t len; /* number of entries */
|
||||||
slot slots[]; /* slots[0] reserved: key low32=class_id, key high32=rec_id, val=opaque */
|
slot slots[]; /* slots[0] reserved: key low32=class_id, key high32=rec_id, val=opaque */
|
||||||
} JSRecord;
|
} JSRecord;
|
||||||
@@ -1071,6 +1067,13 @@ static JS_BOOL JSText_equal_ascii (const JSText *text, JSValue imm) {
|
|||||||
enough to call the interrupt callback often. */
|
enough to call the interrupt callback often. */
|
||||||
#define JS_INTERRUPT_COUNTER_INIT 10000
|
#define JS_INTERRUPT_COUNTER_INIT 10000
|
||||||
|
|
||||||
|
/* Auto-rooted C call argv — GC updates values in-place */
|
||||||
|
typedef struct CCallRoot {
|
||||||
|
JSValue *argv; /* points to C-stack-local array */
|
||||||
|
int argc;
|
||||||
|
struct CCallRoot *prev; /* stack for nesting (C -> JS -> C -> ...) */
|
||||||
|
} CCallRoot;
|
||||||
|
|
||||||
struct JSContext {
|
struct JSContext {
|
||||||
JSRuntime *rt;
|
JSRuntime *rt;
|
||||||
|
|
||||||
@@ -1102,6 +1105,7 @@ struct JSContext {
|
|||||||
|
|
||||||
JSGCRef *top_gc_ref; /* used to reference temporary GC roots (stack top) */
|
JSGCRef *top_gc_ref; /* used to reference temporary GC roots (stack top) */
|
||||||
JSGCRef *last_gc_ref; /* used to reference temporary GC roots (list) */
|
JSGCRef *last_gc_ref; /* used to reference temporary GC roots (list) */
|
||||||
|
CCallRoot *c_call_root; /* stack of auto-rooted C call argv arrays */
|
||||||
|
|
||||||
int class_count; /* size of class_array and class_proto */
|
int class_count; /* size of class_array and class_proto */
|
||||||
JSClass *class_array;
|
JSClass *class_array;
|
||||||
@@ -1234,7 +1238,7 @@ typedef struct JSRegExp {
|
|||||||
|
|
||||||
/* Get prototype from object (works for both JSRecord and JSRecord since they
|
/* Get prototype from object (works for both JSRecord and JSRecord since they
|
||||||
* share layout) */
|
* share layout) */
|
||||||
#define JS_OBJ_GET_PROTO(p) ((JSRecord *)((JSRecord *)(p))->proto)
|
#define JS_OBJ_GET_PROTO(p) (JS_IsNull(((JSRecord *)(p))->proto) ? NULL : (JSRecord *)JS_VALUE_GET_PTR(((JSRecord *)(p))->proto))
|
||||||
|
|
||||||
/* Initial capacity for new records (mask = 7, 8 slots total) */
|
/* Initial capacity for new records (mask = 7, 8 slots total) */
|
||||||
#define JS_RECORD_INITIAL_MASK 7
|
#define JS_RECORD_INITIAL_MASK 7
|
||||||
|
|||||||
410
source/runtime.c
410
source/runtime.c
@@ -510,7 +510,7 @@ JSValue rec_get (JSContext *ctx, JSRecord *rec, JSValue k) {
|
|||||||
while (p) {
|
while (p) {
|
||||||
int slot = rec_find_slot (p, k);
|
int slot = rec_find_slot (p, k);
|
||||||
if (slot > 0) { return p->slots[slot].val; }
|
if (slot > 0) { return p->slots[slot].val; }
|
||||||
p = p->proto;
|
p = JS_IsNull (p->proto) ? NULL : JS_VALUE_GET_RECORD (p->proto);
|
||||||
}
|
}
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
@@ -540,7 +540,7 @@ int rec_resize (JSContext *ctx, JSValue *pobj, uint64_t new_mask) {
|
|||||||
|
|
||||||
/* Initialize new record */
|
/* Initialize new record */
|
||||||
new_rec->mist_hdr = objhdr_make (new_mask, OBJ_RECORD, false, false, false, false);
|
new_rec->mist_hdr = objhdr_make (new_mask, OBJ_RECORD, false, false, false, false);
|
||||||
new_rec->proto = rec->proto;
|
new_rec->proto = rec->proto; /* JSValue — copies directly */
|
||||||
new_rec->len = 0;
|
new_rec->len = 0;
|
||||||
|
|
||||||
/* Initialize all slots to empty */
|
/* Initialize all slots to empty */
|
||||||
@@ -646,7 +646,7 @@ JSRecord *js_new_record_class (JSContext *ctx, uint32_t initial_mask, JSClassID
|
|||||||
if (!rec) return NULL;
|
if (!rec) return NULL;
|
||||||
|
|
||||||
rec->mist_hdr = objhdr_make (initial_mask, OBJ_RECORD, false, false, false, false);
|
rec->mist_hdr = objhdr_make (initial_mask, OBJ_RECORD, false, false, false, false);
|
||||||
rec->proto = NULL;
|
rec->proto = JS_NULL;
|
||||||
rec->len = 0;
|
rec->len = 0;
|
||||||
|
|
||||||
/* Initialize all slots to empty (JS_NULL) */
|
/* Initialize all slots to empty (JS_NULL) */
|
||||||
@@ -1038,7 +1038,7 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != OBJ_ARRAY && type != OBJ_TEXT && type != OBJ_RECORD && type != OBJ_FUNCTION && type != OBJ_BLOB && type != OBJ_FRAME) {
|
if (type != OBJ_ARRAY && type != OBJ_TEXT && type != OBJ_RECORD && type != OBJ_FUNCTION && type != OBJ_FRAME) {
|
||||||
fprintf (stderr, "gc_copy_value: invalid object type %d at %p (hdr=0x%llx)\n", type, ptr, (unsigned long long)hdr);
|
fprintf (stderr, "gc_copy_value: invalid object type %d at %p (hdr=0x%llx)\n", type, ptr, (unsigned long long)hdr);
|
||||||
fprintf (stderr, " This may be an interior pointer or corrupt root\n");
|
fprintf (stderr, " This may be an interior pointer or corrupt root\n");
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
@@ -1079,15 +1079,11 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
|||||||
JSRecord *rec = (JSRecord *)ptr;
|
JSRecord *rec = (JSRecord *)ptr;
|
||||||
uint32_t mask = (uint32_t)objhdr_cap56 (rec->mist_hdr);
|
uint32_t mask = (uint32_t)objhdr_cap56 (rec->mist_hdr);
|
||||||
#ifdef DUMP_GC_DETAIL
|
#ifdef DUMP_GC_DETAIL
|
||||||
printf(" record: slots=%u used=%u proto=%p\n", mask + 1, (uint32_t)rec->len, (void*)rec->proto);
|
printf(" record: slots=%u used=%u proto=0x%llx\n", mask + 1, (uint32_t)rec->len, (unsigned long long)rec->proto);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
#endif
|
#endif
|
||||||
/* Copy prototype */
|
/* Copy prototype */
|
||||||
if (rec->proto) {
|
rec->proto = gc_copy_value (ctx, rec->proto, from_base, from_end, to_base, to_free, to_end);
|
||||||
JSValue proto_val = JS_MKPTR (rec->proto);
|
|
||||||
proto_val = gc_copy_value (ctx, proto_val, from_base, from_end, to_base, to_free, to_end);
|
|
||||||
rec->proto = (JSRecord *)JS_VALUE_GET_PTR (proto_val);
|
|
||||||
}
|
|
||||||
/* Copy table entries */
|
/* Copy table entries */
|
||||||
for (uint32_t i = 0; i <= mask; i++) {
|
for (uint32_t i = 0; i <= mask; i++) {
|
||||||
JSValue k = rec->slots[i].key;
|
JSValue k = rec->slots[i].key;
|
||||||
@@ -1127,15 +1123,14 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OBJ_TEXT:
|
case OBJ_TEXT:
|
||||||
case OBJ_BLOB:
|
|
||||||
/* No internal references to scan */
|
/* No internal references to scan */
|
||||||
break;
|
break;
|
||||||
case OBJ_FRAME: {
|
case OBJ_FRAME: {
|
||||||
/* JSFrame - scan function, caller, and slots */
|
/* JSFrame - scan function, caller, address, and slots */
|
||||||
JSFrame *frame = (JSFrame *)ptr;
|
JSFrame *frame = (JSFrame *)ptr;
|
||||||
/* function and caller are now JSValues - copy them directly */
|
|
||||||
frame->function = gc_copy_value (ctx, frame->function, from_base, from_end, to_base, to_free, to_end);
|
frame->function = gc_copy_value (ctx, frame->function, from_base, from_end, to_base, to_free, to_end);
|
||||||
frame->caller = gc_copy_value (ctx, frame->caller, from_base, from_end, to_base, to_free, to_end);
|
frame->caller = gc_copy_value (ctx, frame->caller, from_base, from_end, to_base, to_free, to_end);
|
||||||
|
frame->address = gc_copy_value (ctx, frame->address, from_base, from_end, to_base, to_free, to_end);
|
||||||
/* Scan all slots */
|
/* Scan all slots */
|
||||||
uint64_t slot_count = objhdr_cap56 (frame->header);
|
uint64_t slot_count = objhdr_cap56 (frame->header);
|
||||||
for (uint64_t i = 0; i < slot_count; i++) {
|
for (uint64_t i = 0; i < slot_count; i++) {
|
||||||
@@ -1251,6 +1246,13 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
|||||||
ref->val = gc_copy_value (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
ref->val = gc_copy_value (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy auto-rooted C call argv arrays */
|
||||||
|
for (CCallRoot *r = ctx->c_call_root; r != NULL; r = r->prev) {
|
||||||
|
for (int i = 0; i < r->argc; i++) {
|
||||||
|
r->argv[i] = gc_copy_value (ctx, r->argv[i], from_base, from_end, to_base, &to_free, to_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Cheney scan: scan copied objects to find more references */
|
/* Cheney scan: scan copied objects to find more references */
|
||||||
uint8_t *scan = to_base;
|
uint8_t *scan = to_base;
|
||||||
#ifdef DUMP_GC_DETAIL
|
#ifdef DUMP_GC_DETAIL
|
||||||
@@ -1410,6 +1412,7 @@ JSContext *JS_NewContextRawWithHeapSize (JSRuntime *rt, size_t heap_size) {
|
|||||||
|
|
||||||
/* Initialize register VM frame root */
|
/* Initialize register VM frame root */
|
||||||
ctx->reg_current_frame = JS_NULL;
|
ctx->reg_current_frame = JS_NULL;
|
||||||
|
ctx->c_call_root = NULL;
|
||||||
|
|
||||||
/* Initialize per-context execution state (moved from JSRuntime) */
|
/* Initialize per-context execution state (moved from JSRuntime) */
|
||||||
ctx->current_exception = JS_NULL;
|
ctx->current_exception = JS_NULL;
|
||||||
@@ -2205,7 +2208,7 @@ JSValue JS_NewObjectProtoClass (JSContext *ctx, JSValue proto_val, JSClassID cla
|
|||||||
|
|
||||||
/* Set prototype if provided */
|
/* Set prototype if provided */
|
||||||
if (JS_IsRecord (proto_val)) {
|
if (JS_IsRecord (proto_val)) {
|
||||||
rec->proto = JS_VALUE_GET_RECORD (proto_val);
|
rec->proto = proto_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JS_MKPTR (rec);
|
return JS_MKPTR (rec);
|
||||||
@@ -2685,8 +2688,8 @@ int JS_HasProperty (JSContext *ctx, JSValue obj, JSValue prop) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ret = JS_GetOwnPropertyInternal (ctx, NULL, p, prop);
|
ret = JS_GetOwnPropertyInternal (ctx, NULL, p, prop);
|
||||||
if (ret != 0) return ret;
|
if (ret != 0) return ret;
|
||||||
p = p->proto; /* Direct pointer chase is safe - no allocation */
|
if (JS_IsNull (p->proto)) break;
|
||||||
if (!p) break;
|
p = JS_VALUE_GET_RECORD (p->proto);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -2965,7 +2968,8 @@ int JS_HasPropertyKey (JSContext *ctx, JSValue obj, JSValue key) {
|
|||||||
/* Check own and prototype chain */
|
/* Check own and prototype chain */
|
||||||
while (rec) {
|
while (rec) {
|
||||||
if (rec_find_slot (rec, key) > 0) return TRUE;
|
if (rec_find_slot (rec, key) > 0) return TRUE;
|
||||||
rec = rec->proto;
|
if (JS_IsNull (rec->proto)) break;
|
||||||
|
rec = JS_VALUE_GET_RECORD (rec->proto);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -3902,8 +3906,8 @@ __maybe_unused void JS_DumpObject (JSRuntime *rt, JSRecord *rec) {
|
|||||||
|
|
||||||
printf ("%14p ", (void *)rec);
|
printf ("%14p ", (void *)rec);
|
||||||
/* Print prototype from JSRecord */
|
/* Print prototype from JSRecord */
|
||||||
if (rec->proto) {
|
if (!JS_IsNull (rec->proto)) {
|
||||||
printf ("%14p ", (void *)rec->proto);
|
printf ("%14p ", JS_VALUE_GET_PTR (rec->proto));
|
||||||
} else {
|
} else {
|
||||||
printf ("%14s ", "-");
|
printf ("%14s ", "-");
|
||||||
}
|
}
|
||||||
@@ -3993,20 +3997,20 @@ static JSValue js_throw_type_error (JSContext *ctx, JSValue this_val, int argc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv) {
|
JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv) {
|
||||||
JSCFunctionType func;
|
JSFunction *f = JS_VALUE_GET_FUNCTION (func_obj);
|
||||||
JSFunction *f;
|
JSCFunctionEnum cproto = f->u.cfunc.cproto;
|
||||||
|
JSCFunctionType func = f->u.cfunc.c_function;
|
||||||
JSValue ret_val;
|
JSValue ret_val;
|
||||||
JSValue *arg_buf;
|
|
||||||
int arg_count, i;
|
|
||||||
JSCFunctionEnum cproto;
|
|
||||||
|
|
||||||
f = JS_VALUE_GET_FUNCTION (func_obj);
|
/* Auto-root argv: copy to C stack and register as GC root.
|
||||||
cproto = f->u.cfunc.cproto;
|
GC will update arg_copy[] in-place, so C functions can read
|
||||||
arg_count = f->length;
|
argv[n] across allocation points without manual guarding. */
|
||||||
|
JSValue arg_copy[argc > 0 ? argc : 1];
|
||||||
|
if (argc > 0)
|
||||||
|
memcpy (arg_copy, argv, argc * sizeof (JSValue));
|
||||||
|
|
||||||
arg_buf = argv;
|
CCallRoot root = { arg_copy, argc, ctx->c_call_root };
|
||||||
|
ctx->c_call_root = &root;
|
||||||
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;
|
js_debug dbg;
|
||||||
@@ -4016,16 +4020,14 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
|||||||
|
|
||||||
switch (cproto) {
|
switch (cproto) {
|
||||||
case JS_CFUNC_generic:
|
case JS_CFUNC_generic:
|
||||||
ret_val = func.generic (ctx, this_obj, argc, arg_buf);
|
ret_val = func.generic (ctx, this_obj, argc, arg_copy);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_generic_magic:
|
case JS_CFUNC_generic_magic:
|
||||||
ret_val
|
ret_val = func.generic_magic (ctx, this_obj, argc, arg_copy, f->u.cfunc.magic);
|
||||||
= func.generic_magic (ctx, this_obj, argc, arg_buf, f->u.cfunc.magic);
|
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_f_f: {
|
case JS_CFUNC_f_f: {
|
||||||
double d1;
|
double d1;
|
||||||
|
if (unlikely (JS_ToFloat64 (ctx, &d1, arg_copy[0]))) {
|
||||||
if (unlikely (JS_ToFloat64 (ctx, &d1, arg_buf[0]))) {
|
|
||||||
ret_val = JS_EXCEPTION;
|
ret_val = JS_EXCEPTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -4033,56 +4035,57 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
|||||||
} break;
|
} break;
|
||||||
case JS_CFUNC_f_f_f: {
|
case JS_CFUNC_f_f_f: {
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
|
if (unlikely (JS_ToFloat64 (ctx, &d1, arg_copy[0]))) {
|
||||||
if (unlikely (JS_ToFloat64 (ctx, &d1, arg_buf[0]))) {
|
|
||||||
ret_val = JS_EXCEPTION;
|
ret_val = JS_EXCEPTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (unlikely (JS_ToFloat64 (ctx, &d2, arg_buf[1]))) {
|
if (unlikely (JS_ToFloat64 (ctx, &d2, arg_copy[1]))) {
|
||||||
ret_val = JS_EXCEPTION;
|
ret_val = JS_EXCEPTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret_val = JS_NewFloat64 (ctx, func.f_f_f (d1, d2));
|
ret_val = JS_NewFloat64 (ctx, func.f_f_f (d1, d2));
|
||||||
} break;
|
} break;
|
||||||
/* Fixed-arity fast paths - direct call without argc/argv marshaling */
|
/* Fixed-arity fast paths — args passed by value at dispatch time */
|
||||||
case JS_CFUNC_0:
|
case JS_CFUNC_0:
|
||||||
ret_val = func.f0 (ctx, this_obj);
|
ret_val = func.f0 (ctx, this_obj);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_1:
|
case JS_CFUNC_1:
|
||||||
ret_val = func.f1 (ctx, this_obj, arg_buf[0]);
|
ret_val = func.f1 (ctx, this_obj, arg_copy[0]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_2:
|
case JS_CFUNC_2:
|
||||||
ret_val = func.f2 (ctx, this_obj, arg_buf[0], arg_buf[1]);
|
ret_val = func.f2 (ctx, this_obj, arg_copy[0], arg_copy[1]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_3:
|
case JS_CFUNC_3:
|
||||||
ret_val = func.f3 (ctx, this_obj, arg_buf[0], arg_buf[1], arg_buf[2]);
|
ret_val = func.f3 (ctx, this_obj, arg_copy[0], arg_copy[1], arg_copy[2]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_4:
|
case JS_CFUNC_4:
|
||||||
ret_val = func.f4 (ctx, this_obj, arg_buf[0], arg_buf[1], arg_buf[2], arg_buf[3]);
|
ret_val = func.f4 (ctx, this_obj, arg_copy[0], arg_copy[1], arg_copy[2], arg_copy[3]);
|
||||||
break;
|
break;
|
||||||
/* Pure functions (no this_val) */
|
/* Pure functions (no this_val) */
|
||||||
case JS_CFUNC_PURE:
|
case JS_CFUNC_PURE:
|
||||||
ret_val = func.pure (ctx, argc, arg_buf);
|
ret_val = func.pure (ctx, argc, arg_copy);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_PURE_0:
|
case JS_CFUNC_PURE_0:
|
||||||
ret_val = func.pure0 (ctx);
|
ret_val = func.pure0 (ctx);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_PURE_1:
|
case JS_CFUNC_PURE_1:
|
||||||
ret_val = func.pure1 (ctx, arg_buf[0]);
|
ret_val = func.pure1 (ctx, arg_copy[0]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_PURE_2:
|
case JS_CFUNC_PURE_2:
|
||||||
ret_val = func.pure2 (ctx, arg_buf[0], arg_buf[1]);
|
ret_val = func.pure2 (ctx, arg_copy[0], arg_copy[1]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_PURE_3:
|
case JS_CFUNC_PURE_3:
|
||||||
ret_val = func.pure3 (ctx, arg_buf[0], arg_buf[1], arg_buf[2]);
|
ret_val = func.pure3 (ctx, arg_copy[0], arg_copy[1], arg_copy[2]);
|
||||||
break;
|
break;
|
||||||
case JS_CFUNC_PURE_4:
|
case JS_CFUNC_PURE_4:
|
||||||
ret_val = func.pure4 (ctx, arg_buf[0], arg_buf[1], arg_buf[2], arg_buf[3]);
|
ret_val = func.pure4 (ctx, arg_copy[0], arg_copy[1], arg_copy[2], arg_copy[3]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx->c_call_root = root.prev;
|
||||||
|
|
||||||
if (unlikely (ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
if (unlikely (ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
||||||
ctx->trace_hook (ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
ctx->trace_hook (ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
||||||
|
|
||||||
@@ -7868,20 +7871,12 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* array.reduce(arr, fn, initial, reverse) */
|
/* array.reduce(arr, fn, initial, reverse) */
|
||||||
/* GC-safe reduce: re-chase array after each call */
|
|
||||||
static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
if (argc < 2) return JS_NULL;
|
if (argc < 2) return JS_NULL;
|
||||||
if (!JS_IsArray (argv[0])) return JS_NULL;
|
if (!JS_IsArray (argv[0])) return JS_NULL;
|
||||||
if (!JS_IsFunction (argv[1])) return JS_NULL;
|
if (!JS_IsFunction (argv[1])) return JS_NULL;
|
||||||
|
|
||||||
/* GC-safe: root argv[0] and argv[1] for the duration of this function */
|
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
JSGCRef arr_ref, func_ref;
|
|
||||||
JS_PushGCRef (ctx, &arr_ref);
|
|
||||||
JS_PushGCRef (ctx, &func_ref);
|
|
||||||
arr_ref.val = argv[0];
|
|
||||||
func_ref.val = argv[1];
|
|
||||||
|
|
||||||
JSArray *arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
|
||||||
word_t len = arr->len;
|
word_t len = arr->len;
|
||||||
|
|
||||||
int reverse = argc > 3 && JS_ToBool (ctx, argv[3]);
|
int reverse = argc > 3 && JS_ToBool (ctx, argv[3]);
|
||||||
@@ -7889,65 +7884,63 @@ static JSValue js_cell_array_reduce (JSContext *ctx, JSValue this_val, int argc,
|
|||||||
JSValue acc;
|
JSValue acc;
|
||||||
|
|
||||||
if (argc < 3 || JS_IsNull (argv[2])) {
|
if (argc < 3 || JS_IsNull (argv[2])) {
|
||||||
if (len == 0) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_NULL; }
|
if (len == 0) return JS_NULL;
|
||||||
if (len == 1) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return arr->values[0]; }
|
if (len == 1) return arr->values[0];
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
acc = arr->values[len - 1];
|
acc = arr->values[len - 1];
|
||||||
for (word_t i = len - 1; i > 0; i--) {
|
for (word_t i = len - 1; i > 0; i--) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i - 1 >= arr->len) continue;
|
if (i - 1 >= arr->len) continue;
|
||||||
JSValue args[2] = { acc, arr->values[i - 1] };
|
JSValue args[2] = { acc, arr->values[i - 1] };
|
||||||
JS_PUSH_VALUE (ctx, acc);
|
JS_PUSH_VALUE (ctx, acc);
|
||||||
JSValue new_acc = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
JS_POP_VALUE (ctx, acc);
|
JS_POP_VALUE (ctx, acc);
|
||||||
if (JS_IsException (new_acc)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (new_acc)) return JS_EXCEPTION;
|
||||||
acc = new_acc;
|
acc = new_acc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
acc = arr->values[0];
|
acc = arr->values[0];
|
||||||
for (word_t i = 1; i < len; i++) {
|
for (word_t i = 1; i < len; i++) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
JSValue args[2] = { acc, arr->values[i] };
|
JSValue args[2] = { acc, arr->values[i] };
|
||||||
JS_PUSH_VALUE (ctx, acc);
|
JS_PUSH_VALUE (ctx, acc);
|
||||||
JSValue new_acc = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
JS_POP_VALUE (ctx, acc);
|
JS_POP_VALUE (ctx, acc);
|
||||||
if (JS_IsException (new_acc)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (new_acc)) return JS_EXCEPTION;
|
||||||
acc = new_acc;
|
acc = new_acc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (len == 0) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return argv[2]; }
|
if (len == 0) return argv[2];
|
||||||
acc = argv[2];
|
acc = argv[2];
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (word_t i = len; i > 0; i--) {
|
for (word_t i = len; i > 0; i--) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i - 1 >= arr->len) continue;
|
if (i - 1 >= arr->len) continue;
|
||||||
JSValue args[2] = { acc, arr->values[i - 1] };
|
JSValue args[2] = { acc, arr->values[i - 1] };
|
||||||
JS_PUSH_VALUE (ctx, acc);
|
JS_PUSH_VALUE (ctx, acc);
|
||||||
JSValue new_acc = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
JS_POP_VALUE (ctx, acc);
|
JS_POP_VALUE (ctx, acc);
|
||||||
if (JS_IsException (new_acc)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (new_acc)) return JS_EXCEPTION;
|
||||||
acc = new_acc;
|
acc = new_acc;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (word_t i = 0; i < len; i++) {
|
for (word_t i = 0; i < len; i++) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
JSValue args[2] = { acc, arr->values[i] };
|
JSValue args[2] = { acc, arr->values[i] };
|
||||||
JS_PUSH_VALUE (ctx, acc);
|
JS_PUSH_VALUE (ctx, acc);
|
||||||
JSValue new_acc = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue new_acc = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
JS_POP_VALUE (ctx, acc);
|
JS_POP_VALUE (ctx, acc);
|
||||||
if (JS_IsException (new_acc)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (new_acc)) return JS_EXCEPTION;
|
||||||
acc = new_acc;
|
acc = new_acc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7957,185 +7950,139 @@ static JSValue js_cell_array_for (JSContext *ctx, JSValue this_val, int argc, JS
|
|||||||
if (!JS_IsArray (argv[0])) return JS_NULL;
|
if (!JS_IsArray (argv[0])) return JS_NULL;
|
||||||
if (!JS_IsFunction (argv[1])) return JS_NULL;
|
if (!JS_IsFunction (argv[1])) return JS_NULL;
|
||||||
|
|
||||||
/* GC-safe: root argv[0] and argv[1] */
|
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
JSGCRef arr_ref, func_ref;
|
|
||||||
JS_PushGCRef (ctx, &arr_ref);
|
|
||||||
JS_PushGCRef (ctx, &func_ref);
|
|
||||||
arr_ref.val = argv[0];
|
|
||||||
func_ref.val = argv[1];
|
|
||||||
|
|
||||||
JSArray *arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
|
||||||
|
|
||||||
word_t len = arr->len;
|
word_t len = arr->len;
|
||||||
if (len == 0) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_NULL; }
|
if (len == 0) return JS_NULL;
|
||||||
|
|
||||||
int reverse = argc > 2 && JS_ToBool (ctx, argv[2]);
|
int reverse = argc > 2 && JS_ToBool (ctx, argv[2]);
|
||||||
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
|
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
|
||||||
|
|
||||||
/* Determine function arity */
|
/* Determine function arity */
|
||||||
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (func_ref.val))->length;
|
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (argv[1]))->length;
|
||||||
|
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (word_t i = len; i > 0; i--) {
|
for (word_t i = len; i > 0; i--) {
|
||||||
/* Re-chase array each iteration */
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
|
||||||
if (i - 1 >= arr->len) continue;
|
if (i - 1 >= arr->len) continue;
|
||||||
JSValue result;
|
JSValue result;
|
||||||
if (arity == 1) {
|
if (arity == 1) {
|
||||||
JSValue item = arr->values[i - 1];
|
JSValue item = arr->values[i - 1];
|
||||||
result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &item, 0);
|
result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
|
||||||
} else {
|
} else {
|
||||||
JSValue args[2];
|
JSValue args[2];
|
||||||
args[0] = arr->values[i - 1];
|
args[0] = arr->values[i - 1];
|
||||||
args[1] = JS_NewInt32 (ctx, (int32_t)(i - 1));
|
args[1] = JS_NewInt32 (ctx, (int32_t)(i - 1));
|
||||||
result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
}
|
}
|
||||||
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val))
|
||||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val)) {
|
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (word_t i = 0; i < len; i++) {
|
for (word_t i = 0; i < len; i++) {
|
||||||
/* Re-chase array each iteration */
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
JSValue result;
|
JSValue result;
|
||||||
if (arity == 1) {
|
if (arity == 1) {
|
||||||
JSValue item = arr->values[i];
|
JSValue item = arr->values[i];
|
||||||
result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &item, 0);
|
result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
|
||||||
} else {
|
} else {
|
||||||
JSValue args[2];
|
JSValue args[2];
|
||||||
args[0] = arr->values[i];
|
args[0] = arr->values[i];
|
||||||
args[1] = JS_NewInt32 (ctx, (int32_t)i);
|
args[1] = JS_NewInt32 (ctx, (int32_t)i);
|
||||||
result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
}
|
}
|
||||||
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val))
|
||||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, result, exit_val)) {
|
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* array.find(arr, fn, reverse, from) */
|
/* array.find(arr, fn_or_value, reverse, from) */
|
||||||
/* array.find(arr, fn, reverse, from) - GC-safe */
|
|
||||||
static JSValue js_cell_array_find (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
static JSValue js_cell_array_find (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
if (argc < 2) return JS_NULL;
|
if (argc < 2) return JS_NULL;
|
||||||
if (!JS_IsArray (argv[0])) return JS_NULL;
|
if (!JS_IsArray (argv[0])) return JS_NULL;
|
||||||
|
|
||||||
/* GC-safe: root argv[0] */
|
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
JSGCRef arr_ref;
|
|
||||||
JS_PushGCRef (ctx, &arr_ref);
|
|
||||||
arr_ref.val = argv[0];
|
|
||||||
|
|
||||||
JSArray *arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
|
||||||
word_t len = arr->len;
|
word_t len = arr->len;
|
||||||
|
|
||||||
int reverse = argc > 2 && JS_ToBool (ctx, argv[2]);
|
int reverse = argc > 2 && JS_ToBool (ctx, argv[2]);
|
||||||
int32_t from;
|
int32_t from;
|
||||||
if (argc > 3 && !JS_IsNull (argv[3])) {
|
if (argc > 3 && !JS_IsNull (argv[3])) {
|
||||||
if (JS_ToInt32 (ctx, &from, argv[3])) { JS_PopGCRef (ctx, &arr_ref); return JS_NULL; }
|
if (JS_ToInt32 (ctx, &from, argv[3])) return JS_NULL;
|
||||||
} else {
|
} else {
|
||||||
from = reverse ? (int32_t)(len - 1) : 0;
|
from = reverse ? (int32_t)(len - 1) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS_IsFunction (argv[1])) {
|
if (!JS_IsFunction (argv[1])) {
|
||||||
/* Compare exactly - no GC concerns since no calls */
|
|
||||||
JSValue target = argv[1];
|
JSValue target = argv[1];
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (int32_t i = from; i >= 0; i--) {
|
for (int32_t i = from; i >= 0; i--) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if ((word_t)i >= arr->len) continue;
|
if ((word_t)i >= arr->len) continue;
|
||||||
if (js_strict_eq (ctx, arr->values[i], target)) {
|
if (js_strict_eq (ctx, arr->values[i], target))
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, i);
|
return JS_NewInt32 (ctx, i);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (word_t i = (word_t)from; i < len; i++) {
|
for (word_t i = (word_t)from; i < len; i++) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
if (js_strict_eq (ctx, arr->values[i], target)) {
|
if (js_strict_eq (ctx, arr->values[i], target))
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, (int32_t)i);
|
return JS_NewInt32 (ctx, (int32_t)i);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use function predicate - must re-chase after each call */
|
/* Use function predicate — re-chase after each call */
|
||||||
JSGCRef func_ref;
|
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (argv[1]))->length;
|
||||||
JS_PushGCRef (ctx, &func_ref);
|
|
||||||
func_ref.val = argv[1];
|
|
||||||
int arity = ((JSFunction *)JS_VALUE_GET_FUNCTION (func_ref.val))->length;
|
|
||||||
|
|
||||||
if (arity == 2) {
|
if (arity == 2) {
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (int32_t i = from; i >= 0; i--) {
|
for (int32_t i = from; i >= 0; i--) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if ((word_t)i >= arr->len) continue;
|
if ((word_t)i >= arr->len) continue;
|
||||||
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
|
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_ToBool (ctx, result)) {
|
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, i);
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (word_t i = (word_t)from; i < len; i++) {
|
for (word_t i = (word_t)from; i < len; i++) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, (int32_t)i) };
|
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, (int32_t)i) };
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 2, args, 0);
|
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 2, args, 0);
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_ToBool (ctx, result)) {
|
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, (int32_t)i);
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, (int32_t)i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
for (int32_t i = from; i >= 0; i--) {
|
for (int32_t i = from; i >= 0; i--) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if ((word_t)i >= arr->len) continue;
|
if ((word_t)i >= arr->len) continue;
|
||||||
JSValue item = arr->values[i];
|
JSValue item = arr->values[i];
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &item, 0);
|
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_ToBool (ctx, result)) {
|
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, i);
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (word_t i = (word_t)from; i < len; i++) {
|
for (word_t i = (word_t)from; i < len; i++) {
|
||||||
arr = JS_VALUE_GET_ARRAY (arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (i >= arr->len) break;
|
if (i >= arr->len) break;
|
||||||
JSValue item = arr->values[i];
|
JSValue item = arr->values[i];
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &item, 0);
|
JSValue result = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &item, 0);
|
||||||
if (JS_IsException (result)) { JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref); return JS_EXCEPTION; }
|
if (JS_IsException (result)) return JS_EXCEPTION;
|
||||||
if (JS_ToBool (ctx, result)) {
|
if (JS_ToBool (ctx, result)) return JS_NewInt32 (ctx, (int32_t)i);
|
||||||
JS_PopGCRef (ctx, &func_ref); JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NewInt32 (ctx, (int32_t)i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8604,55 +8551,29 @@ static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSV
|
|||||||
if (argc < 1) return JS_NULL;
|
if (argc < 1) return JS_NULL;
|
||||||
if (!JS_IsFunction (argv[0])) return argv[0];
|
if (!JS_IsFunction (argv[0])) return argv[0];
|
||||||
|
|
||||||
JSGCRef func_ref, args_ref;
|
if (argc < 2)
|
||||||
JS_PushGCRef (ctx, &func_ref);
|
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||||
JS_PushGCRef (ctx, &args_ref);
|
|
||||||
func_ref.val = argv[0];
|
|
||||||
args_ref.val = argc >= 2 ? argv[1] : JS_NULL;
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (!JS_IsArray (argv[1]))
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 0, NULL, 0);
|
return JS_CallInternal (ctx, argv[0], JS_NULL, 1, &argv[1], 0);
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!JS_IsArray (args_ref.val)) {
|
JSArray *arr = JS_VALUE_GET_ARRAY (argv[1]);
|
||||||
/* Wrap single value in array */
|
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 1, &args_ref.val, 0);
|
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSArray *arr = JS_VALUE_GET_ARRAY (args_ref.val);
|
|
||||||
int len = arr->len;
|
int len = arr->len;
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0)
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, 0, NULL, 0);
|
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValue *args = js_malloc (ctx, sizeof (JSValue) * len);
|
JSValue *args = js_malloc (ctx, sizeof (JSValue) * len);
|
||||||
if (!args) {
|
if (!args) return JS_EXCEPTION;
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
arr = JS_VALUE_GET_ARRAY (argv[1]); /* re-chase after malloc */
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return JS_EXCEPTION;
|
|
||||||
}
|
|
||||||
arr = JS_VALUE_GET_ARRAY (args_ref.val); /* re-chase after malloc via rooted ref */
|
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
args[i] = arr->values[i];
|
args[i] = arr->values[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue result = JS_CallInternal (ctx, func_ref.val, JS_NULL, len, args, 0);
|
JSValue result = JS_CallInternal (ctx, argv[0], JS_NULL, len, args, 0);
|
||||||
|
|
||||||
js_free (ctx, args);
|
js_free (ctx, args);
|
||||||
|
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9233,15 +9154,9 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
|
|
||||||
JSValue env = (argc >= 2 && mist_is_gc_object (argv[1])) ? argv[1] : JS_NULL;
|
JSValue env = (argc >= 2 && mist_is_gc_object (argv[1])) ? argv[1] : JS_NULL;
|
||||||
|
|
||||||
JSGCRef env_ref;
|
JSCodeRegister *code = JS_LoadMachCode (ctx, mc, env);
|
||||||
JS_PushGCRef (ctx, &env_ref);
|
|
||||||
env_ref.val = env;
|
|
||||||
|
|
||||||
JSCodeRegister *code = JS_LoadMachCode (ctx, mc, env_ref.val);
|
|
||||||
JS_FreeMachCode (mc);
|
JS_FreeMachCode (mc);
|
||||||
JSValue result = JS_CallRegisterVM (ctx, code, ctx->global_obj, 0, NULL, env_ref.val, JS_NULL);
|
return JS_CallRegisterVM (ctx, code, ctx->global_obj, 0, NULL, env, JS_NULL);
|
||||||
JS_PopGCRef (ctx, &env_ref);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mach_eval_mcode(name, mcode_json, env?) - compile mcode IR and run via register VM */
|
/* mach_eval_mcode(name, mcode_json, env?) - compile mcode IR and run via register VM */
|
||||||
@@ -9281,14 +9196,9 @@ static JSValue js_mach_eval_mcode (JSContext *ctx, JSValue this_val, int argc, J
|
|||||||
|
|
||||||
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
|
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
|
||||||
|
|
||||||
JSGCRef env_ref;
|
JSCodeRegister *code = JS_LoadMachCode (ctx, mc, env);
|
||||||
JS_PushGCRef (ctx, &env_ref);
|
|
||||||
env_ref.val = env;
|
|
||||||
|
|
||||||
JSCodeRegister *code = JS_LoadMachCode (ctx, mc, env_ref.val);
|
|
||||||
JS_FreeMachCode (mc);
|
JS_FreeMachCode (mc);
|
||||||
JSValue result = JS_CallRegisterVM (ctx, code, ctx->global_obj, 0, NULL, env_ref.val, JS_NULL);
|
JSValue result = JS_CallRegisterVM (ctx, code, ctx->global_obj, 0, NULL, env, JS_NULL);
|
||||||
JS_PopGCRef (ctx, &env_ref);
|
|
||||||
JS_FreeCString (ctx, name);
|
JS_FreeCString (ctx, name);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -9328,18 +9238,13 @@ static JSValue js_mach_dump_mcode (JSContext *ctx, JSValue this_val, int argc, J
|
|||||||
|
|
||||||
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
|
JSValue env = (argc >= 3 && mist_is_gc_object (argv[2])) ? argv[2] : JS_NULL;
|
||||||
|
|
||||||
JSGCRef env_ref;
|
|
||||||
JS_PushGCRef (ctx, &env_ref);
|
|
||||||
env_ref.val = env;
|
|
||||||
|
|
||||||
/* Serialize to binary then dump */
|
/* Serialize to binary then dump */
|
||||||
size_t bin_size;
|
size_t bin_size;
|
||||||
uint8_t *bin = JS_SerializeMachCode (mc, &bin_size);
|
uint8_t *bin = JS_SerializeMachCode (mc, &bin_size);
|
||||||
JS_FreeMachCode (mc);
|
JS_FreeMachCode (mc);
|
||||||
JS_DumpMachBin (ctx, bin, bin_size, env_ref.val);
|
JS_DumpMachBin (ctx, bin, bin_size, env);
|
||||||
sys_free (bin);
|
sys_free (bin);
|
||||||
|
|
||||||
JS_PopGCRef (ctx, &env_ref);
|
|
||||||
JS_FreeCString (ctx, name);
|
JS_FreeCString (ctx, name);
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
@@ -9888,19 +9793,11 @@ static JSValue js_cell_push (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
|
|
||||||
if (!JS_IsArray (argv[0])) return JS_NULL;
|
if (!JS_IsArray (argv[0])) return JS_NULL;
|
||||||
|
|
||||||
JSGCRef arr_ref;
|
|
||||||
JS_PushGCRef (ctx, &arr_ref);
|
|
||||||
arr_ref.val = argv[0];
|
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (js_intrinsic_array_push (ctx, &arr_ref.val, argv[i]) < 0) {
|
if (js_intrinsic_array_push (ctx, &argv[0], argv[i]) < 0)
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
argv[0] = arr_ref.val;
|
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10171,50 +10068,34 @@ static JSValue js_cell_call (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
return JS_ThrowTypeError (ctx, "call requires a function argument");
|
return JS_ThrowTypeError (ctx, "call requires a function argument");
|
||||||
|
|
||||||
JSGCRef func_ref, this_ref, args_ref;
|
if (!JS_IsFunction (argv[0]))
|
||||||
JS_PushGCRef (ctx, &func_ref);
|
|
||||||
JS_PushGCRef (ctx, &this_ref);
|
|
||||||
JS_PushGCRef (ctx, &args_ref);
|
|
||||||
func_ref.val = argv[0];
|
|
||||||
this_ref.val = argc >= 2 ? argv[1] : JS_NULL;
|
|
||||||
args_ref.val = argc >= 3 ? argv[2] : JS_NULL;
|
|
||||||
|
|
||||||
if (!JS_IsFunction (func_ref.val)) {
|
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &this_ref);
|
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return JS_ThrowTypeError (ctx, "first argument must be a function");
|
return JS_ThrowTypeError (ctx, "first argument must be a function");
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 3 || JS_IsNull (args_ref.val)) {
|
JSGCRef this_ref;
|
||||||
JSValue ret = JS_CallInternal (ctx, func_ref.val, this_ref.val, 0, NULL, 0);
|
JS_PushGCRef (ctx, &this_ref);
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
this_ref.val = argc >= 2 ? argv[1] : JS_NULL;
|
||||||
|
|
||||||
|
if (argc < 3 || JS_IsNull (argv[2])) {
|
||||||
|
JSValue ret = JS_CallInternal (ctx, argv[0], this_ref.val, 0, NULL, 0);
|
||||||
JS_PopGCRef (ctx, &this_ref);
|
JS_PopGCRef (ctx, &this_ref);
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS_IsArray (args_ref.val)) {
|
if (!JS_IsArray (argv[2])) {
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &this_ref);
|
JS_PopGCRef (ctx, &this_ref);
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return JS_ThrowTypeError (ctx, "third argument must be an array");
|
return JS_ThrowTypeError (ctx, "third argument must be an array");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
JSValue *tab = build_arg_list (ctx, &len, &args_ref.val);
|
JSValue *tab = build_arg_list (ctx, &len, &argv[2]);
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &this_ref);
|
JS_PopGCRef (ctx, &this_ref);
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue ret = JS_CallInternal (ctx, func_ref.val, this_ref.val, len, tab, 0);
|
JSValue ret = JS_CallInternal (ctx, argv[0], this_ref.val, len, tab, 0);
|
||||||
free_arg_list (ctx, tab, len);
|
free_arg_list (ctx, tab, len);
|
||||||
JS_PopGCRef (ctx, &args_ref);
|
|
||||||
JS_PopGCRef (ctx, &this_ref);
|
JS_PopGCRef (ctx, &this_ref);
|
||||||
JS_PopGCRef (ctx, &func_ref);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10395,32 +10276,17 @@ static JSValue js_cell_ends_with(JSContext *ctx, JSValue this_val, int argc, JSV
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* every(arr, pred) — find(arr, x => !pred(x)) == null */
|
/* every(arr, pred) — find(arr, x => !pred(x)) == null */
|
||||||
static JSValue js_cell_every(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
static JSValue js_cell_every (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
if (argc < 2) return JS_NULL;
|
if (argc < 2) return JS_NULL;
|
||||||
if (!JS_IsArray(argv[0]) || !JS_IsFunction(argv[1])) return JS_NULL;
|
if (!JS_IsArray (argv[0]) || !JS_IsFunction (argv[1])) return JS_NULL;
|
||||||
JSGCRef arr_ref, fn_ref;
|
JSArray *arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
JS_PushGCRef(ctx, &arr_ref);
|
|
||||||
JS_PushGCRef(ctx, &fn_ref);
|
|
||||||
arr_ref.val = argv[0];
|
|
||||||
fn_ref.val = argv[1];
|
|
||||||
JSArray *arr = JS_VALUE_GET_ARRAY(arr_ref.val);
|
|
||||||
for (int i = 0; i < arr->len; i++) {
|
for (int i = 0; i < arr->len; i++) {
|
||||||
JSValue elem = arr->values[i];
|
JSValue elem = arr->values[i];
|
||||||
JSValue r = JS_CallInternal(ctx, fn_ref.val, JS_NULL, 1, &elem, 0);
|
JSValue r = JS_CallInternal (ctx, argv[1], JS_NULL, 1, &elem, 0);
|
||||||
arr = JS_VALUE_GET_ARRAY(arr_ref.val);
|
arr = JS_VALUE_GET_ARRAY (argv[0]);
|
||||||
if (JS_IsException(r)) {
|
if (JS_IsException (r)) return r;
|
||||||
JS_PopGCRef(ctx, &fn_ref);
|
if (!JS_ToBool (ctx, r)) return JS_FALSE;
|
||||||
JS_PopGCRef(ctx, &arr_ref);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
if (!JS_ToBool(ctx, r)) {
|
|
||||||
JS_PopGCRef(ctx, &fn_ref);
|
|
||||||
JS_PopGCRef(ctx, &arr_ref);
|
|
||||||
return JS_FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
JS_PopGCRef(ctx, &fn_ref);
|
|
||||||
JS_PopGCRef(ctx, &arr_ref);
|
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user