Merge branch 'fix_gc' into pitweb
This commit is contained in:
256
source/runtime.c
256
source/runtime.c
@@ -183,6 +183,25 @@ void JS_DeleteGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
}
|
||||
}
|
||||
|
||||
/* JS_FRAME/JS_ROOT/JS_LOCAL helper functions */
|
||||
JSGCRef *JS_GetGCFrame (JSContext *ctx) {
|
||||
return ctx->top_gc_ref;
|
||||
}
|
||||
|
||||
JSLocalRef *JS_GetLocalFrame (JSContext *ctx) {
|
||||
return ctx->top_local_ref;
|
||||
}
|
||||
|
||||
void JS_PushLocalRef (JSContext *ctx, JSLocalRef *ref) {
|
||||
ref->prev = ctx->top_local_ref;
|
||||
ctx->top_local_ref = ref;
|
||||
}
|
||||
|
||||
void JS_RestoreFrame (JSContext *ctx, JSGCRef *gc_frame, JSLocalRef *local_frame) {
|
||||
ctx->top_gc_ref = gc_frame;
|
||||
ctx->top_local_ref = local_frame;
|
||||
}
|
||||
|
||||
void *ct_alloc (JSContext *ctx, size_t bytes, size_t align) {
|
||||
/* Align the request */
|
||||
bytes = (bytes + align - 1) & ~(align - 1);
|
||||
@@ -1300,8 +1319,6 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
|
||||
|
||||
for (;;) {
|
||||
void *ptr = JS_VALUE_GET_PTR (v);
|
||||
if (is_ct_ptr (ctx, ptr)) return v;
|
||||
|
||||
if (!ptr_in_range (ptr, from_base, from_end)) return v;
|
||||
|
||||
objhdr_t *hdr_ptr = (objhdr_t *)ptr;
|
||||
@@ -1608,6 +1625,14 @@ 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);
|
||||
}
|
||||
|
||||
/* Copy JS_LOCAL roots (update C locals through pointers) */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: top_local_ref\n"); fflush(stdout);
|
||||
#endif
|
||||
for (JSLocalRef *ref = ctx->top_local_ref; ref != NULL; ref = ref->prev) {
|
||||
*ref->ptr = gc_copy_value (ctx, *ref->ptr, from_base, from_end, to_base, &to_free, to_end);
|
||||
}
|
||||
|
||||
/* Copy JS_AddGCRef/JS_DeleteGCRef roots */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: last_gc_ref\n"); fflush(stdout);
|
||||
@@ -1651,6 +1676,10 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
|
||||
/* Update context with new block */
|
||||
size_t new_used = to_free - to_base;
|
||||
|
||||
/* Update GC stats */
|
||||
ctx->gc_count++;
|
||||
ctx->gc_bytes_copied += new_used;
|
||||
size_t recovered = old_used > new_used ? old_used - new_used : 0;
|
||||
|
||||
ctx->heap_base = to_base;
|
||||
@@ -1670,19 +1699,23 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If <20% recovered, double next block size for future allocations
|
||||
But only if allow_grow is set (i.e., GC was triggered due to low space) */
|
||||
/* If <40% recovered, grow next block size for future allocations.
|
||||
First poor recovery: double. Consecutive poor: quadruple. */
|
||||
#ifdef DUMP_GC
|
||||
int will_grow = 0;
|
||||
#endif
|
||||
if (allow_grow && recovered > 0 && old_used > 0 && recovered < old_used / 5) {
|
||||
size_t doubled = new_size * 2;
|
||||
if (doubled <= buddy_max_block(&ctx->rt->buddy)) {
|
||||
ctx->next_block_size = doubled;
|
||||
if (allow_grow && recovered > 0 && old_used > 0 && recovered < old_used * 2 / 5) {
|
||||
size_t factor = ctx->gc_poor_streak >= 1 ? 4 : 2;
|
||||
size_t grown = new_size * factor;
|
||||
if (grown <= buddy_max_block(&ctx->rt->buddy)) {
|
||||
ctx->next_block_size = grown;
|
||||
#ifdef DUMP_GC
|
||||
will_grow = 1;
|
||||
#endif
|
||||
}
|
||||
ctx->gc_poor_streak++;
|
||||
} else {
|
||||
ctx->gc_poor_streak = 0;
|
||||
}
|
||||
|
||||
#ifdef DUMP_GC
|
||||
@@ -1828,6 +1861,20 @@ JSContext *JS_NewContextRawWithHeapSize (JSRuntime *rt, size_t heap_size) {
|
||||
/* Initialize per-context execution state (moved from JSRuntime) */
|
||||
ctx->current_exception = JS_NULL;
|
||||
|
||||
/* Initialize constant text pool (avoids overflow pages for common case) */
|
||||
{
|
||||
size_t ct_pool_size = 64 * 1024; /* 64KB initial CT pool */
|
||||
ctx->ct_base = js_malloc_rt (ct_pool_size);
|
||||
if (!ctx->ct_base) {
|
||||
js_free_rt (ctx->class_array);
|
||||
js_free_rt (ctx->class_proto);
|
||||
js_free_rt (ctx);
|
||||
return NULL;
|
||||
}
|
||||
ctx->ct_free = ctx->ct_base;
|
||||
ctx->ct_end = ctx->ct_base + ct_pool_size;
|
||||
}
|
||||
|
||||
/* Initialize constant text intern table */
|
||||
ctx->ct_pages = NULL;
|
||||
ctx->ct_array = NULL;
|
||||
@@ -1917,6 +1964,7 @@ void JS_FreeContext (JSContext *ctx) {
|
||||
|
||||
/* Free constant text pool and intern table */
|
||||
ct_free_all (ctx);
|
||||
if (ctx->ct_base) js_free_rt (ctx->ct_base);
|
||||
js_free_rt (ctx->ct_hash);
|
||||
js_free_rt (ctx->ct_array);
|
||||
|
||||
@@ -2109,8 +2157,24 @@ static JSValue js_sub_string_val (JSContext *ctx, JSValue src, int start, int en
|
||||
return js_new_string8_len (ctx, buf, len);
|
||||
}
|
||||
|
||||
/* Heap string — fast path for short ASCII substrings (avoids heap alloc) */
|
||||
JSText *p = JS_VALUE_GET_STRING (src);
|
||||
if (len <= MIST_ASCII_MAX_LEN) {
|
||||
char buf[MIST_ASCII_MAX_LEN];
|
||||
int all_ascii = 1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint32_t c = string_get (p, start + i);
|
||||
if (c >= 0x80) { all_ascii = 0; break; }
|
||||
buf[i] = (char)c;
|
||||
}
|
||||
if (all_ascii) {
|
||||
JSValue imm = MIST_TryNewImmediateASCII (buf, len);
|
||||
if (!JS_IsNull (imm)) return imm;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heap string — delegate to existing js_sub_string */
|
||||
return js_sub_string (ctx, JS_VALUE_GET_STRING (src), start, end);
|
||||
return js_sub_string (ctx, p, start, end);
|
||||
}
|
||||
|
||||
/* Allocate a new pretext (mutable JSText) with initial capacity */
|
||||
@@ -2619,11 +2683,51 @@ JSValue JS_NewArrayLen (JSContext *ctx, uint32_t len) {
|
||||
|
||||
JSValue JS_NewArray (JSContext *ctx) { return JS_NewArrayLen (ctx, 0); }
|
||||
|
||||
/* Create array with pre-allocated capacity but len=0 (for push-fill patterns) */
|
||||
JSValue JS_NewArrayCap (JSContext *ctx, uint32_t cap) {
|
||||
if (cap == 0) cap = JS_ARRAY_INITIAL_SIZE;
|
||||
size_t values_size = sizeof (JSValue) * cap;
|
||||
size_t total_size = sizeof (JSArray) + values_size;
|
||||
JSArray *arr = js_malloc (ctx, total_size);
|
||||
if (!arr) return JS_EXCEPTION;
|
||||
arr->mist_hdr = objhdr_make (cap, OBJ_ARRAY, false, false, false, false);
|
||||
arr->len = 0;
|
||||
for (uint32_t i = 0; i < cap; i++)
|
||||
arr->values[i] = JS_NULL;
|
||||
return JS_MKPTR (arr);
|
||||
}
|
||||
|
||||
JSValue JS_NewObject (JSContext *ctx) {
|
||||
/* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
|
||||
return JS_NewObjectProtoClass (ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
|
||||
}
|
||||
|
||||
/* Create object with pre-allocated hash table for n properties */
|
||||
JSValue JS_NewObjectCap (JSContext *ctx, uint32_t n) {
|
||||
/* slot 0 is reserved, so need n+1 slots minimum.
|
||||
Hash table needs ~2x entries for good load factor.
|
||||
mask must be power-of-2 minus 1. */
|
||||
uint32_t need = (n + 1) * 2;
|
||||
uint32_t mask = JS_RECORD_INITIAL_MASK;
|
||||
while (mask + 1 < need) mask = (mask << 1) | 1;
|
||||
|
||||
JSGCRef proto_ref;
|
||||
JS_PushGCRef (ctx, &proto_ref);
|
||||
proto_ref.val = ctx->class_proto[JS_CLASS_OBJECT];
|
||||
|
||||
JSRecord *rec = js_new_record_class (ctx, mask, JS_CLASS_OBJECT);
|
||||
|
||||
JSValue proto_val = proto_ref.val;
|
||||
JS_PopGCRef (ctx, &proto_ref);
|
||||
|
||||
if (!rec) return JS_EXCEPTION;
|
||||
|
||||
if (JS_IsRecord (proto_val))
|
||||
rec->proto = proto_val;
|
||||
|
||||
return JS_MKPTR (rec);
|
||||
}
|
||||
|
||||
|
||||
/* Note: at least 'length' arguments will be readable in 'argv' */
|
||||
static JSValue JS_NewCFunction3 (JSContext *ctx, JSCFunction *func, const char *name, int length, JSCFunctionEnum cproto, int magic) {
|
||||
@@ -4383,6 +4487,10 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
||||
ctx->trace_hook (ctx, JS_HOOK_CALL, &dbg, ctx->trace_data);
|
||||
}
|
||||
|
||||
#ifdef VALIDATE_GC
|
||||
uint8_t *pre_heap_base = ctx->heap_base;
|
||||
#endif
|
||||
|
||||
switch (cproto) {
|
||||
case JS_CFUNC_generic:
|
||||
ret_val = func.generic (ctx, this_obj, argc, arg_copy);
|
||||
@@ -4449,6 +4557,21 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
||||
abort ();
|
||||
}
|
||||
|
||||
#ifdef VALIDATE_GC
|
||||
if (ctx->heap_base != pre_heap_base && JS_IsPtr (ret_val)) {
|
||||
void *rp = JS_VALUE_GET_PTR (ret_val);
|
||||
if (!is_ct_ptr (ctx, rp) &&
|
||||
((uint8_t *)rp < ctx->heap_base || (uint8_t *)rp >= ctx->heap_free)) {
|
||||
/* Note: f is stale after GC (func_obj was passed by value), so we
|
||||
cannot read f->name here. Just report the pointer. */
|
||||
fprintf (stderr, "VALIDATE_GC: C function returned stale ptr=%p "
|
||||
"heap=[%p,%p) after GC\n", rp,
|
||||
(void *)ctx->heap_base, (void *)ctx->heap_free);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx->c_call_root = root.prev;
|
||||
|
||||
if (unlikely (ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
||||
@@ -5356,19 +5479,27 @@ static JSValue cjson_to_jsvalue (JSContext *ctx, const cJSON *item) {
|
||||
if (cJSON_IsString (item)) return JS_NewString (ctx, item->valuestring);
|
||||
if (cJSON_IsArray (item)) {
|
||||
int n = cJSON_GetArraySize (item);
|
||||
JSValue arr = JS_NewArrayLen (ctx,n);
|
||||
JSGCRef arr_ref;
|
||||
JS_AddGCRef (ctx, &arr_ref);
|
||||
arr_ref.val = JS_NewArrayLen (ctx, n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
cJSON *child = cJSON_GetArrayItem (item, i);
|
||||
JS_SetPropertyNumber (ctx, arr, i, cjson_to_jsvalue (ctx, child));
|
||||
JS_SetPropertyNumber (ctx, arr_ref.val, i, cjson_to_jsvalue (ctx, child));
|
||||
}
|
||||
return arr;
|
||||
JSValue result = arr_ref.val;
|
||||
JS_DeleteGCRef (ctx, &arr_ref);
|
||||
return result;
|
||||
}
|
||||
if (cJSON_IsObject (item)) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
JSGCRef obj_ref;
|
||||
JS_AddGCRef (ctx, &obj_ref);
|
||||
obj_ref.val = JS_NewObject (ctx);
|
||||
for (cJSON *child = item->child; child; child = child->next) {
|
||||
JS_SetPropertyStr (ctx, obj, child->string, cjson_to_jsvalue (ctx, child));
|
||||
JS_SetPropertyStr (ctx, obj_ref.val, child->string, cjson_to_jsvalue (ctx, child));
|
||||
}
|
||||
return obj;
|
||||
JSValue result = obj_ref.val;
|
||||
JS_DeleteGCRef (ctx, &obj_ref);
|
||||
return result;
|
||||
}
|
||||
return JS_NULL;
|
||||
}
|
||||
@@ -7857,8 +7988,8 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
|
||||
|
||||
JSGCRef result_ref;
|
||||
JS_PushGCRef (ctx, &result_ref); /* Push first - sets val to JS_NULL */
|
||||
result_ref.val = JS_NewArray (ctx); /* Then assign */
|
||||
JS_PushGCRef (ctx, &result_ref);
|
||||
result_ref.val = JS_NewArrayLen (ctx, len);
|
||||
if (JS_IsException (result_ref.val)) {
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
JS_PopGCRef (ctx, &arg1_ref);
|
||||
@@ -7866,17 +7997,23 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
return result_ref.val;
|
||||
}
|
||||
|
||||
int out_idx = 0;
|
||||
#define MAP_STORE(val) do { \
|
||||
JSArray *out = JS_VALUE_GET_ARRAY (result_ref.val); \
|
||||
out->values[out_idx++] = (val); \
|
||||
} while(0)
|
||||
#define MAP_ERR() do { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; } while(0)
|
||||
|
||||
if (arity >= 2) {
|
||||
if (reverse) {
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
/* Re-chase input array each iteration */
|
||||
arr = JS_VALUE_GET_ARRAY (arg0_ref.val);
|
||||
if (i >= (int)arr->len) continue; /* array may have shrunk */
|
||||
if (i >= (int)arr->len) continue;
|
||||
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
|
||||
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 2, args, 0);
|
||||
if (JS_IsException (val)) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
if (JS_IsException (val)) { MAP_ERR (); }
|
||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
|
||||
if (js_intrinsic_array_push (ctx, &result_ref.val, val) < 0) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
MAP_STORE (val);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
@@ -7884,9 +8021,9 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
if (i >= (int)arr->len) break;
|
||||
JSValue args[2] = { arr->values[i], JS_NewInt32 (ctx, i) };
|
||||
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 2, args, 0);
|
||||
if (JS_IsException (val)) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
if (JS_IsException (val)) { MAP_ERR (); }
|
||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
|
||||
if (js_intrinsic_array_push (ctx, &result_ref.val, val) < 0) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
MAP_STORE (val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -7896,9 +8033,9 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
if (i >= (int)arr->len) continue;
|
||||
JSValue item = arr->values[i];
|
||||
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 1, &item, 0);
|
||||
if (JS_IsException (val)) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
if (JS_IsException (val)) { MAP_ERR (); }
|
||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
|
||||
if (js_intrinsic_array_push (ctx, &result_ref.val, val) < 0) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
MAP_STORE (val);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
@@ -7906,12 +8043,17 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
if (i >= (int)arr->len) break;
|
||||
JSValue item = arr->values[i];
|
||||
JSValue val = JS_CallInternal (ctx, arg1_ref.val, JS_NULL, 1, &item, 0);
|
||||
if (JS_IsException (val)) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
if (JS_IsException (val)) { MAP_ERR (); }
|
||||
if (!JS_IsNull (exit_val) && js_strict_eq (ctx, val, exit_val)) break;
|
||||
if (js_intrinsic_array_push (ctx, &result_ref.val, val) < 0) { JS_PopGCRef (ctx, &result_ref); JS_PopGCRef (ctx, &arg1_ref); JS_PopGCRef (ctx, &arg0_ref); return JS_EXCEPTION; }
|
||||
MAP_STORE (val);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef MAP_STORE
|
||||
#undef MAP_ERR
|
||||
/* Truncate if early exit produced fewer elements */
|
||||
JSArray *out = JS_VALUE_GET_ARRAY (result_ref.val);
|
||||
out->len = out_idx;
|
||||
JSValue result = result_ref.val;
|
||||
JS_PopGCRef (ctx, &result_ref);
|
||||
JS_PopGCRef (ctx, &arg1_ref);
|
||||
@@ -8018,7 +8160,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
JS_PushGCRef (ctx, &arr_ref);
|
||||
JS_PushGCRef (ctx, &str_ref);
|
||||
str_ref.val = arg;
|
||||
arr_ref.val = JS_NewArray (ctx);
|
||||
arr_ref.val = JS_NewArrayLen (ctx, len);
|
||||
if (JS_IsException (arr_ref.val)) {
|
||||
JS_PopGCRef (ctx, &str_ref);
|
||||
JS_PopGCRef (ctx, &arr_ref);
|
||||
@@ -8031,7 +8173,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
|
||||
JS_PopGCRef (ctx, &arr_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JS_ArrayPush (ctx, &arr_ref.val, ch);
|
||||
JS_SetPropertyNumber (ctx, arr_ref.val, i, ch);
|
||||
}
|
||||
JSValue result = arr_ref.val;
|
||||
JS_PopGCRef (ctx, &str_ref);
|
||||
@@ -9636,6 +9778,22 @@ static JSValue js_mach_dump_mcode (JSContext *ctx, JSValue this_val, int argc, J
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* gc_stats() — return {count, bytes_copied, heap_size, ct_pages} and reset counters */
|
||||
static JSValue js_gc_stats (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
if (JS_IsException (obj)) return obj;
|
||||
JS_SetPropertyStr (ctx, obj, "count", JS_NewInt64 (ctx, (int64_t)ctx->gc_count));
|
||||
JS_SetPropertyStr (ctx, obj, "bytes_copied", JS_NewInt64 (ctx, (int64_t)ctx->gc_bytes_copied));
|
||||
JS_SetPropertyStr (ctx, obj, "heap_size", JS_NewInt64 (ctx, (int64_t)ctx->current_block_size));
|
||||
/* Count CT overflow pages */
|
||||
int ct_page_count = 0;
|
||||
for (CTPage *p = (CTPage *)ctx->ct_pages; p; p = p->next) ct_page_count++;
|
||||
JS_SetPropertyStr (ctx, obj, "ct_pages", JS_NewInt32 (ctx, ct_page_count));
|
||||
ctx->gc_count = 0;
|
||||
ctx->gc_bytes_copied = 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* mach_compile_mcode_bin(name, mcode_json) - compile mcode IR to serialized binary blob */
|
||||
static JSValue js_mach_compile_mcode_bin (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
|
||||
@@ -10128,16 +10286,13 @@ JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue
|
||||
JSValue JS_NewArrayFrom (JSContext *ctx, int count, JSValue *values) {
|
||||
JSGCRef arr_ref;
|
||||
JS_PushGCRef (ctx, &arr_ref);
|
||||
arr_ref.val = JS_NewArray (ctx);
|
||||
arr_ref.val = JS_NewArrayLen (ctx, count);
|
||||
if (JS_IsException (arr_ref.val)) {
|
||||
JS_PopGCRef (ctx, &arr_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (JS_ArrayPush (ctx, &arr_ref.val, values[i]) < 0) {
|
||||
JS_PopGCRef (ctx, &arr_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JS_SetPropertyNumber (ctx, arr_ref.val, i, values[i]);
|
||||
}
|
||||
JSValue result = arr_ref.val;
|
||||
JS_PopGCRef (ctx, &arr_ref);
|
||||
@@ -10731,6 +10886,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
||||
js_set_global_cfunc(ctx, "mach_eval_mcode", js_mach_eval_mcode, 3);
|
||||
js_set_global_cfunc(ctx, "mach_dump_mcode", js_mach_dump_mcode, 3);
|
||||
js_set_global_cfunc(ctx, "mach_compile_mcode_bin", js_mach_compile_mcode_bin, 2);
|
||||
js_set_global_cfunc(ctx, "gc_stats", js_gc_stats, 0);
|
||||
js_set_global_cfunc(ctx, "stone", js_cell_stone, 1);
|
||||
js_set_global_cfunc(ctx, "length", js_cell_length, 1);
|
||||
js_set_global_cfunc(ctx, "call", js_cell_call, 3);
|
||||
@@ -11009,7 +11165,7 @@ static char *js_do_nota_decode (JSContext *js, JSValue *tmp, char *nota, JSValue
|
||||
break;
|
||||
case NOTA_ARR:
|
||||
nota = nota_read_array (&n, nota);
|
||||
*tmp = JS_NewArray (js);
|
||||
*tmp = JS_NewArrayLen (js, n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
nota = js_do_nota_decode (js, &ret2, nota, *tmp, JS_NewInt32 (js, i), reviver);
|
||||
JS_SetPropertyNumber (js, *tmp, i, ret2);
|
||||
@@ -11879,9 +12035,13 @@ static const JSCFunctionListEntry js_math_radians_funcs[]
|
||||
JS_CFUNC_DEF ("e", 1, js_math_e) };
|
||||
|
||||
JSValue js_core_math_radians_use (JSContext *ctx) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj, js_math_radians_funcs, countof (js_math_radians_funcs));
|
||||
return obj;
|
||||
JSGCRef obj_ref;
|
||||
JS_PushGCRef (ctx, &obj_ref);
|
||||
obj_ref.val = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj_ref.val, js_math_radians_funcs, countof (js_math_radians_funcs));
|
||||
JSValue result = obj_ref.val;
|
||||
JS_PopGCRef (ctx, &obj_ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -11945,9 +12105,13 @@ static const JSCFunctionListEntry js_math_degrees_funcs[]
|
||||
JS_CFUNC_DEF ("e", 1, js_math_e) };
|
||||
|
||||
JSValue js_core_math_degrees_use (JSContext *ctx) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj, js_math_degrees_funcs, countof (js_math_degrees_funcs));
|
||||
return obj;
|
||||
JSGCRef obj_ref;
|
||||
JS_PushGCRef (ctx, &obj_ref);
|
||||
obj_ref.val = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj_ref.val, js_math_degrees_funcs, countof (js_math_degrees_funcs));
|
||||
JSValue result = obj_ref.val;
|
||||
JS_PopGCRef (ctx, &obj_ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -12010,9 +12174,13 @@ static const JSCFunctionListEntry js_math_cycles_funcs[]
|
||||
JS_CFUNC_DEF ("e", 1, js_math_e) };
|
||||
|
||||
JSValue js_core_math_cycles_use (JSContext *ctx) {
|
||||
JSValue obj = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj, js_math_cycles_funcs, countof (js_math_cycles_funcs));
|
||||
return obj;
|
||||
JSGCRef obj_ref;
|
||||
JS_PushGCRef (ctx, &obj_ref);
|
||||
obj_ref.val = JS_NewObject (ctx);
|
||||
JS_SetPropertyFunctionList (ctx, obj_ref.val, js_math_cycles_funcs, countof (js_math_cycles_funcs));
|
||||
JSValue result = obj_ref.val;
|
||||
JS_PopGCRef (ctx, &obj_ref);
|
||||
return result;
|
||||
}
|
||||
/* Public API: get stack trace as cJSON array */
|
||||
cJSON *JS_GetStack(JSContext *ctx) {
|
||||
|
||||
Reference in New Issue
Block a user