use unstone jstext for string creation

This commit is contained in:
2026-02-18 17:39:22 -06:00
parent 91b73f923a
commit 81561d426b
6 changed files with 207 additions and 251 deletions

View File

@@ -115,7 +115,7 @@ static JSValue js_miniz_compress(JSContext *js, JSValue this_val,
/* ─── 2. Allocate an output buffer big enough ────────────── */
mz_ulong out_len_est = mz_compressBound(in_len);
void *out_buf = js_malloc(js, out_len_est);
void *out_buf = js_malloc_rt(out_len_est);
if (!out_buf) {
if (cstring) JS_FreeCString(js, cstring);
return JS_EXCEPTION;
@@ -130,14 +130,14 @@ static JSValue js_miniz_compress(JSContext *js, JSValue this_val,
if (cstring) JS_FreeCString(js, cstring);
if (st != MZ_OK) {
js_free(js, out_buf);
js_free_rt(out_buf);
return JS_ThrowInternalError(js,
"miniz: compression failed (%d)", st);
}
/* ─── 4. Hand JavaScript a copy of the compressed data ────── */
JSValue abuf = js_new_blob_stoned_copy(js, out_buf, out_len);
js_free(js, out_buf);
js_free_rt(out_buf);
return abuf;
}

View File

@@ -116,7 +116,7 @@ static void encode_js_object(json_encoder *enc, JSContext *js, JSValue obj) {
JS_FreeCString(js, key);
JS_FreeAtom(js, props[i].atom);
}
js_free(js, props);
js_free_rt(props);
}
enc->endTable(enc);
}

37
qop.c
View File

@@ -84,11 +84,11 @@ static qop_desc *js2qop(JSContext *js, JSValue v) {
static int js_qop_ensure_index(JSContext *js, qop_desc *qop) {
if (qop->hashmap != NULL) return 1;
void *buffer = js_malloc(js, qop->hashmap_size);
void *buffer = js_malloc_rt(qop->hashmap_size);
if (!buffer) return 0;
int num = qop_read_index(qop, buffer);
if (num == 0) {
js_free(js, buffer);
js_free_rt(buffer);
return 0;
}
return 1;
@@ -102,13 +102,13 @@ JSC_CCALL(qop_open,
else if (!data)
ret = JS_ThrowReferenceError(js, "Empty blob");
else {
qop_desc *qop = js_malloc(js, sizeof(qop_desc));
qop_desc *qop = js_malloc_rt(sizeof(qop_desc));
if (!qop)
ret = JS_ThrowOutOfMemory(js);
else {
int size = qop_open_data((const unsigned char *)data, len, qop);
if (size == 0) {
js_free(js, qop);
js_free_rt(qop);
ret = JS_ThrowReferenceError(js, "Failed to open QOP archive from blob");
} else {
JSValue obj = JS_NewObjectClass(js, js_qop_archive_class_id);
@@ -127,7 +127,7 @@ JSC_CCALL(qop_write,
JS_FreeCString(js, path);
if (!fh) return JS_ThrowInternalError(js, "Could not open file for writing");
qop_writer *w = js_malloc(js, sizeof(qop_writer));
qop_writer *w = js_malloc_rt(sizeof(qop_writer));
if (!w) {
fclose(fh);
return JS_ThrowOutOfMemory(js);
@@ -137,10 +137,10 @@ JSC_CCALL(qop_write,
w->capacity = 1024;
w->len = 0;
w->size = 0;
w->files = js_malloc(js, sizeof(qop_file) * w->capacity);
w->files = js_malloc_rt(sizeof(qop_file) * w->capacity);
if (!w->files) {
fclose(fh);
js_free(js, w);
js_free_rt(w);
return JS_ThrowOutOfMemory(js);
}
@@ -183,18 +183,18 @@ static JSValue js_qop_read(JSContext *js, JSValue self, int argc, JSValue *argv)
return JS_NULL;
}
unsigned char *dest = js_malloc(js, file->size);
unsigned char *dest = js_malloc_rt(file->size);
if (!dest)
return JS_ThrowOutOfMemory(js);
int bytes = qop_read(qop, file, dest);
if (bytes == 0) {
js_free(js, dest);
js_free_rt(dest);
return JS_ThrowReferenceError(js, "Failed to read file");
}
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
js_free(js, dest);
js_free_rt(dest);
return blob;
}
@@ -223,18 +223,18 @@ static JSValue js_qop_read_ex(JSContext *js, JSValue self, int argc, JSValue *ar
if (JS_ToUint32(js, &start, argv[1]) < 0 || JS_ToUint32(js, &len, argv[2]) < 0)
return JS_ThrowTypeError(js, "Invalid start or len");
unsigned char *dest = js_malloc(js, len);
unsigned char *dest = js_malloc_rt(len);
if (!dest)
return JS_ThrowOutOfMemory(js);
int bytes = qop_read_ex(qop, file, dest, start, len);
if (bytes == 0) {
js_free(js, dest);
js_free_rt(dest);
return JS_ThrowReferenceError(js, "Failed to read file part");
}
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
js_free(js, dest);
js_free_rt(dest);
return blob;
}
@@ -254,19 +254,19 @@ static JSValue js_qop_list(JSContext *js, JSValue self, int argc, JSValue *argv)
qop_file *file = &qop->hashmap[i];
if (file->size == 0) continue; // empty slot
char *path = js_malloc(js, file->path_len);
char *path = js_malloc_rt(file->path_len);
if (!path) {
return JS_ThrowOutOfMemory(js);
}
int len = qop_read_path(qop, file, path);
if (len == 0) {
js_free(js, path);
js_free_rt(path);
continue; // skip on error
}
JSValue str = JS_NewStringLen(js, path, len - 1); // -1 for null terminator
js_free(js, path);
js_free_rt(path);
JS_SetPropertyNumber(js, arr, count++, str);
}
@@ -311,7 +311,7 @@ static JSValue js_qop_is_directory(JSContext *js, JSValue self, int argc, JSValu
// Check if any file starts with path + "/"
size_t path_len = strlen(path);
char *prefix = js_malloc(js, path_len + 2);
char *prefix = alloca(path_len + 2);
memcpy(prefix, path, path_len);
prefix[path_len] = '/';
prefix[path_len + 1] = '\0';
@@ -339,7 +339,6 @@ static JSValue js_qop_is_directory(JSContext *js, JSValue self, int argc, JSValu
}
}
js_free(js, prefix);
JS_FreeCString(js, path);
return JS_NewBool(js, found);
}
@@ -366,7 +365,7 @@ static JSValue js_writer_add_file(JSContext *js, JSValue self, int argc, JSValue
if (w->len >= w->capacity) {
w->capacity *= 2;
qop_file *new_files = js_realloc(js, w->files, sizeof(qop_file) * w->capacity);
qop_file *new_files = realloc(w->files, sizeof(qop_file) * w->capacity);
if (!new_files) {
JS_FreeCString(js, path);
return JS_ThrowOutOfMemory(js);

View File

@@ -230,8 +230,6 @@ static inline JS_BOOL JS_VALUE_IS_NUMBER (JSValue v) {
/* JS_IsPretext, JS_KeyGetStr, JS_PushGCRef, JS_PopGCRef, JS_AddGCRef, JS_DeleteGCRef
are defined after JSContext (they need its fields) */
/* Forward declarations for memory functions (now declared in quickjs.h) */
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
/* Forward declaration for string_get */
static inline int string_get (const JSText *p, int idx);
@@ -1575,7 +1573,6 @@ JSText *pretext_putc (JSContext *ctx, JSText *s, uint32_t c);
JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v);
JSValue js_new_blob (JSContext *ctx, blob *b);
/* Functions from header region (defined in runtime.c) */
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
void *ct_alloc (JSContext *ctx, size_t bytes, size_t align);
void ct_free_all (JSContext *ctx);
int ct_resize (JSContext *ctx);
@@ -1629,13 +1626,6 @@ static inline int to_digit (int c) {
else return 36;
}
no_inline int js_realloc_array (JSContext *ctx, void **parray, int elem_size, int *psize, int req_size);
static inline int js_resize_array (JSContext *ctx, void **parray, int elem_size, int *psize, int req_size) {
if (unlikely (req_size > *psize))
return js_realloc_array (ctx, parray, elem_size, psize, req_size);
else
return 0;
}
JSText *js_alloc_string (JSContext *ctx, int max_len);
JSValue js_key_from_string (JSContext *ctx, JSValue val);

View File

@@ -1007,9 +1007,6 @@ void *js_debugger_val_address (JSContext *js, JSValue val);
============================================================ */
void *js_malloc (JSContext *ctx, size_t size);
void *js_mallocz (JSContext *ctx, size_t size);
void *js_realloc (JSContext *ctx, void *ptr, size_t size);
void js_free (JSContext *ctx, void *ptr);
char *js_strdup (JSContext *ctx, const char *str);
/* Runtime-level memory functions */
void *js_malloc_rt (size_t size);

View File

@@ -291,24 +291,6 @@ int ct_resize (JSContext *ctx) {
return 0;
}
void *js_realloc (JSContext *ctx, void *ptr, size_t size) {
void *new_ptr;
/* Align size to 8 bytes */
size = (size + 7) & ~7;
if (!ptr) {
/* New allocation */
new_ptr = js_malloc (ctx, size);
if (!new_ptr) return NULL;
return new_ptr;
}
/* Bump allocator: just allocate new space.
Caller is responsible for protecting ptr and copying data. */
new_ptr = js_malloc (ctx, size);
return new_ptr;
}
JSValue intern_text_to_value (JSContext *ctx, const uint32_t *utf32, uint32_t len) {
/* Pack UTF-32 for hashing and comparison */
@@ -583,6 +565,8 @@ JSValue rec_get (JSContext *ctx, JSRecord *rec, JSValue k) {
return JS_NULL;
}
size_t gc_object_size (void *ptr); /* forward declaration for growth-forward size storage */
int rec_resize (JSContext *ctx, JSValue *pobj, uint64_t new_mask) {
/* Protect the source object with a GC ref in case js_malloc triggers GC */
JSGCRef obj_ref;
@@ -646,7 +630,9 @@ int rec_resize (JSContext *ctx, JSValue *pobj, uint64_t new_mask) {
}
/* Install forward header at old location so stale references can find the new record */
size_t old_size = gc_object_size (rec);
rec->mist_hdr = objhdr_make_fwd (new_rec);
*((size_t *)((uint8_t *)rec + sizeof (objhdr_t))) = old_size;
/* Update caller's JSValue to point to new record */
*pobj = JS_MKPTR (new_rec);
@@ -865,11 +851,6 @@ void *js_mallocz (JSContext *ctx, size_t size) {
return memset (ptr, 0, size);
}
void js_free (JSContext *ctx, void *ptr) {
/* Bump allocator doesn't free individual allocations - GC handles it */
(void)ctx;
(void)ptr;
}
/* Parser memory functions - use system allocator to avoid GC issues */
@@ -937,41 +918,6 @@ JSValue ppretext_end (JSContext *ctx, PPretext *p) {
return JS_MKPTR (str);
}
no_inline int js_realloc_array (JSContext *ctx, void **parray, int elem_size, int *psize, int req_size) {
int new_size;
void *new_array;
void *old_array = *parray;
int old_size = *psize;
/* XXX: potential arithmetic overflow */
new_size = max_int (req_size, old_size * 3 / 2);
/* Protect source object with a GC ref before allocating (GC may move it) */
JSGCRef src_ref;
JS_PushGCRef (ctx, &src_ref);
if (old_array) {
src_ref.val = JS_MKPTR (old_array);
}
new_array = js_malloc (ctx, new_size * elem_size);
if (!new_array) {
JS_PopGCRef (ctx, &src_ref);
return -1;
}
/* Get possibly-moved source pointer after GC */
if (old_array) {
old_array = (void *)chase (src_ref.val);
memcpy (new_array, old_array, old_size * elem_size);
}
JS_PopGCRef (ctx, &src_ref);
*psize = new_size;
*parray = new_array;
return 0;
}
/* Append a JSValue string to a PPretext (parser pretext) */
PPretext *ppretext_append_jsvalue (PPretext *p, JSValue str) {
@@ -1386,6 +1332,7 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
*to_free += size;
*hdr_ptr = objhdr_make_fwd (new_ptr);
*((size_t *)((uint8_t *)hdr_ptr + sizeof (objhdr_t))) = size;
return JS_MKPTR (new_ptr);
}
@@ -1732,6 +1679,70 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
}
#endif
/* Finalize garbage records that have class finalizers */
{
uint8_t *p = from_base;
uint8_t *prev_p = NULL;
size_t prev_size = 0;
uint8_t prev_type = 0;
while (p < from_end) {
objhdr_t hdr = *(objhdr_t *)p;
uint8_t type = objhdr_type (hdr);
size_t size;
if (type == OBJ_FORWARD) {
size = *((size_t *)(p + sizeof (objhdr_t)));
if (size == 0 || size > (size_t)(from_end - from_base) || (size & 7) != 0) {
uint64_t *w = (uint64_t *)p;
fprintf (stderr, "gc_finalize_walk: bad fwd size=%zu at p=%p prev_p=%p prev_type=%d prev_size=%zu\n"
" words: [0]=0x%llx [1]=0x%llx [2]=0x%llx [3]=0x%llx\n"
" prev words: [0]=0x%llx [1]=0x%llx [2]=0x%llx [3]=0x%llx\n",
size, (void *)p, (void *)prev_p, prev_type, prev_size,
(unsigned long long)w[0], (unsigned long long)w[1],
(unsigned long long)w[2], (unsigned long long)w[3],
prev_p ? ((unsigned long long *)prev_p)[0] : 0,
prev_p ? ((unsigned long long *)prev_p)[1] : 0,
prev_p ? ((unsigned long long *)prev_p)[2] : 0,
prev_p ? ((unsigned long long *)prev_p)[3] : 0);
break;
}
} else if (type != OBJ_ARRAY && type != OBJ_BLOB && type != OBJ_TEXT &&
type != OBJ_RECORD && type != OBJ_FUNCTION && type != OBJ_FRAME) {
uint64_t *w = (uint64_t *)p;
fprintf (stderr, "gc_finalize_walk: bad type=%d at p=%p hdr=0x%llx prev_p=%p prev_type=%d prev_size=%zu\n"
" words: [0]=0x%llx [1]=0x%llx [2]=0x%llx [3]=0x%llx\n"
" prev words: [0]=0x%llx [1]=0x%llx [2]=0x%llx [3]=0x%llx\n",
type, (void *)p, (unsigned long long)hdr, (void *)prev_p, prev_type, prev_size,
(unsigned long long)w[0], (unsigned long long)w[1],
(unsigned long long)w[2], (unsigned long long)w[3],
prev_p ? ((unsigned long long *)prev_p)[0] : 0,
prev_p ? ((unsigned long long *)prev_p)[1] : 0,
prev_p ? ((unsigned long long *)prev_p)[2] : 0,
prev_p ? ((unsigned long long *)prev_p)[3] : 0);
break;
} else {
size = gc_object_size (p);
if (type == OBJ_RECORD) {
JSRecord *rec = (JSRecord *)p;
uint32_t class_id = REC_GET_CLASS_ID (rec);
if (class_id != 0 && (int)class_id < ctx->class_count) {
JSClassFinalizer *fn = ctx->class_array[class_id].finalizer;
if (fn) {
#ifdef DUMP_GC_FINALIZER
fprintf (stderr, "gc_finalize: class_id=%u name=%s rec=%p\n",
class_id, ctx->class_array[class_id].class_name, (void *)rec);
#endif
fn (rt, JS_MKPTR (rec));
}
}
}
}
prev_p = p;
prev_type = type;
prev_size = size;
p += size;
}
}
/* Return old block (in poison mode, just poison it and leak) */
heap_block_free (rt, from_base, old_heap_size);
@@ -2083,6 +2094,37 @@ void JS_FreeContext (JSContext *ctx) {
}
for (i = 0; i < ctx->class_count; i++) {
}
/* Finalize all remaining records with class finalizers before teardown */
if (ctx->heap_base) {
uint8_t *p = ctx->heap_base;
while (p < ctx->heap_free) {
objhdr_t hdr = *(objhdr_t *)p;
uint8_t type = objhdr_type (hdr);
size_t size;
if (type == OBJ_FORWARD) {
size = *((size_t *)(p + sizeof (objhdr_t)));
} else {
size = gc_object_size (p);
if (type == OBJ_RECORD) {
JSRecord *rec = (JSRecord *)p;
uint32_t class_id = REC_GET_CLASS_ID (rec);
if (class_id != 0 && (int)class_id < ctx->class_count) {
JSClassFinalizer *fn = ctx->class_array[class_id].finalizer;
if (fn) {
#ifdef DUMP_GC_FINALIZER
fprintf (stderr, "teardown_finalize: class_id=%u name=%s rec=%p\n",
class_id, ctx->class_array[class_id].class_name, (void *)rec);
#endif
fn (rt, JS_MKPTR (rec));
}
}
}
}
p += size;
}
}
js_free_rt (ctx->class_array);
js_free_rt (ctx->class_proto);
@@ -2454,10 +2496,7 @@ JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v) {
JSValue pretext_end (JSContext *ctx, JSText *s) {
if (!s) return JS_EXCEPTION;
int len = (int)s->length;
if (len == 0) {
js_free (ctx, s);
return JS_KEY_empty;
}
if (len == 0) return JS_KEY_empty;
/* Promote short ASCII strings to immediate values */
if (len <= MIST_ASCII_MAX_LEN) {
char buf[MIST_ASCII_MAX_LEN];
@@ -2957,7 +2996,9 @@ static int js_array_grow (JSContext *ctx, JSValue *arr_ptr, word_t min_cap) {
new_arr->values[i] = JS_NULL;
/* Install forward header at old location */
size_t old_arr_size = gc_object_size (arr);
arr->mist_hdr = objhdr_make_fwd (new_arr);
*((size_t *)((uint8_t *)arr + sizeof (objhdr_t))) = old_arr_size;
/* Update the tracked JSValue to point to new array */
*arr_ptr = JS_MKPTR (new_arr);
@@ -4213,25 +4254,10 @@ static __exception int JS_ToLength (JSContext *ctx, int64_t *plen, JSValue val)
}
static JSValue js_dtoa2 (JSContext *ctx, double d, int radix, int n_digits, int flags) {
char static_buf[128], *buf, *tmp_buf;
int len, len_max;
JSValue res;
char buf[1088];
JSDTOATempMem dtoa_mem;
len_max = js_dtoa_max_len (d, radix, n_digits, flags);
/* longer buffer may be used if radix != 10 */
if (len_max > sizeof (static_buf) - 1) {
tmp_buf = js_malloc (ctx, len_max + 1);
if (!tmp_buf) return JS_EXCEPTION;
buf = tmp_buf;
} else {
tmp_buf = NULL;
buf = static_buf;
}
len = js_dtoa (buf, d, radix, n_digits, flags, &dtoa_mem);
res = js_new_string8_len (ctx, buf, len);
js_free (ctx, tmp_buf);
return res;
int len = js_dtoa (buf, d, radix, n_digits, flags, &dtoa_mem);
return js_new_string8_len (ctx, buf, len);
}
JSValue JS_ToString (JSContext *ctx, JSValue val) {
@@ -5074,7 +5100,7 @@ JSValue js_compile_regexp (JSContext *ctx, JSValue pattern, JSValue flags) {
ret
= js_new_string8_len (ctx, (const char *)re_bytecode_buf, re_bytecode_len);
js_free (ctx, re_bytecode_buf);
js_free_rt (re_bytecode_buf);
return ret;
}
@@ -6182,12 +6208,7 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
return JS_EXCEPTION;
}
char *clean = js_malloc (ctx, strlen (str) + 1);
if (!clean) {
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
return JS_EXCEPTION;
}
char *clean = alloca (strlen (str) + 1);
const char *p = str;
char *q = clean;
@@ -6228,7 +6249,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
*q = '\0';
char *endptr;
long long n = strtoll (str, &endptr, 2);
js_free (ctx, clean);
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
if (endptr == str) return JS_NULL;
@@ -6237,7 +6257,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
*q = '\0';
char *endptr;
long long n = strtoll (str, &endptr, 8);
js_free (ctx, clean);
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
if (endptr == str) return JS_NULL;
@@ -6246,7 +6265,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
*q = '\0';
char *endptr;
long long n = strtoll (str, &endptr, 16);
js_free (ctx, clean);
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
if (endptr == str) return JS_NULL;
@@ -6255,14 +6273,12 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
*q = '\0';
char *endptr;
long long n = strtoll (str, &endptr, 32);
js_free (ctx, clean);
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
if (endptr == str) return JS_NULL;
return JS_NewInt64 (ctx, n);
} else if (strcmp (format, "j") == 0) {
/* JavaScript style prefix */
js_free (ctx, clean);
JS_FreeCString (ctx, format);
int radix = 10;
const char *start = str;
@@ -6294,7 +6310,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
*q = '\0';
double d = strtod (clean, NULL);
js_free (ctx, clean);
JS_FreeCString (ctx, format);
JS_FreeCString (ctx, str);
if (isnan (d)) return JS_NULL;
@@ -6497,13 +6512,9 @@ static JSValue js_cell_number_to_radix_string (JSContext *ctx, double num, int r
return JS_NewString (ctx, result);
}
/* Helper: add separator every n digits from right */
static char *add_separator (JSContext *ctx, const char *str, char sep, int n) {
if (n <= 0) {
char *result = js_malloc (ctx, strlen (str) + 1);
if (result) strcpy (result, str);
return result;
}
/* Helper: add separator every n digits from right, returns JSValue string */
static JSValue add_separator (JSContext *ctx, const char *str, char sep, int n, int prepend_neg) {
if (n <= 0) return JS_NewString (ctx, str);
int negative = (str[0] == '-');
const char *start = negative ? str + 1 : str;
@@ -6511,34 +6522,35 @@ static char *add_separator (JSContext *ctx, const char *str, char sep, int n) {
/* Find decimal point */
const char *decimal = strchr (start, '.');
int int_len = decimal ? (int)(decimal - start) : (int)strlen (start);
int dec_len = decimal ? (int)strlen (decimal) : 0;
int num_seps = (int_len - 1) / n;
int result_len = strlen (str) + num_seps + 1;
char *result = js_malloc (ctx, result_len);
if (!result) return NULL;
int total = (negative ? 1 : 0) + prepend_neg + int_len + num_seps + dec_len;
char *q = result;
if (negative) *q++ = '-';
JSText *pt = pretext_init (ctx, total);
if (!pt) return JS_EXCEPTION;
int pos = 0;
if (prepend_neg) string_put (pt, pos++, '-');
if (negative) string_put (pt, pos++, '-');
int count = int_len % n;
if (count == 0) count = n;
for (int i = 0; i < int_len; i++) {
if (i > 0 && count == 0) {
*q++ = sep;
string_put (pt, pos++, (uint32_t)sep);
count = n;
}
*q++ = start[i];
string_put (pt, pos++, (uint32_t)(unsigned char)start[i]);
count--;
}
if (decimal) {
strcpy (q, decimal);
} else {
*q = '\0';
}
for (int i = 0; i < dec_len; i++)
string_put (pt, pos++, (uint32_t)(unsigned char)decimal[i]);
return result;
pt->length = pos;
return pretext_end (ctx, pt);
}
/* Helper: format number with format string */
@@ -6576,7 +6588,6 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
if (format[i] != '\0') return JS_NULL;
char buf[128];
char *result_str = NULL;
switch (style) {
case 'e': {
@@ -6602,22 +6613,13 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
/* Space separated */
if (separation == 0) separation = 3;
snprintf (buf, sizeof (buf), "%.*f", places, num);
result_str = add_separator (ctx, buf, ' ', separation);
if (!result_str) return JS_EXCEPTION;
JSValue ret = JS_NewString (ctx, result_str);
js_free (ctx, result_str);
return ret;
return add_separator (ctx, buf, ' ', separation, 0);
}
case 'u': {
/* Underbar separated */
snprintf (buf, sizeof (buf), "%.*f", places, num);
if (separation > 0) {
result_str = add_separator (ctx, buf, '_', separation);
if (!result_str) return JS_EXCEPTION;
JSValue ret = JS_NewString (ctx, result_str);
js_free (ctx, result_str);
return ret;
}
if (separation > 0)
return add_separator (ctx, buf, '_', separation, 0);
return JS_NewString (ctx, buf);
}
case 'd':
@@ -6626,11 +6628,7 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
if (separation == 0) separation = 3;
if (places == 0 && style == 'd') places = 2;
snprintf (buf, sizeof (buf), "%.*f", places, num);
result_str = add_separator (ctx, buf, ',', separation);
if (!result_str) return JS_EXCEPTION;
JSValue ret = JS_NewString (ctx, result_str);
js_free (ctx, result_str);
return ret;
return add_separator (ctx, buf, ',', separation, 0);
}
case 'v': {
/* European style: comma decimal, period separator */
@@ -6639,13 +6637,8 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
for (char *p = buf; *p; p++) {
if (*p == '.') *p = ',';
}
if (separation > 0) {
result_str = add_separator (ctx, buf, '.', separation);
if (!result_str) return JS_EXCEPTION;
JSValue ret = JS_NewString (ctx, result_str);
js_free (ctx, result_str);
return ret;
}
if (separation > 0)
return add_separator (ctx, buf, '.', separation, 0);
return JS_NewString (ctx, buf);
}
case 'i': {
@@ -6661,26 +6654,8 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
memmove (buf + (places - len), buf, len + 1);
memset (buf, '0', places - len);
}
if (separation > 0) {
result_str = add_separator (ctx, buf, '_', separation);
if (!result_str) return JS_EXCEPTION;
if (neg) {
char *final = js_malloc (ctx, strlen (result_str) + 2);
if (!final) {
js_free (ctx, result_str);
return JS_EXCEPTION;
}
final[0] = '-';
strcpy (final + 1, result_str);
js_free (ctx, result_str);
JSValue ret = JS_NewString (ctx, final);
js_free (ctx, final);
return ret;
}
JSValue ret = JS_NewString (ctx, result_str);
js_free (ctx, result_str);
return ret;
}
if (separation > 0)
return add_separator (ctx, buf, '_', separation, neg);
if (neg) {
memmove (buf + 1, buf, strlen (buf) + 1);
buf[0] = '-';
@@ -6902,69 +6877,72 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
if (format == 'h') {
static const char hex[] = "0123456789abcdef";
char *result = js_malloc (ctx, byte_len * 2 + 1);
if (!result) return JS_EXCEPTION;
int exact = (int)(byte_len * 2);
JSText *pt = pretext_init (ctx, exact);
if (!pt) return JS_EXCEPTION;
bd = (JSBlob *)chase (argv[0]);
data = (const uint8_t *)bd->bits;
for (size_t i = 0; i < byte_len; i++) {
result[i * 2] = hex[(data[i] >> 4) & 0xF];
result[i * 2 + 1] = hex[data[i] & 0xF];
string_put (pt, (int)(i * 2), (uint32_t)hex[(data[i] >> 4) & 0xF]);
string_put (pt, (int)(i * 2 + 1), (uint32_t)hex[data[i] & 0xF]);
}
result[byte_len * 2] = '\0';
JSValue ret = JS_NewString (ctx, result);
js_free (ctx, result);
return ret;
pt->length = exact;
return pretext_end (ctx, pt);
} else if (format == 'b') {
char *result = js_malloc (ctx, bd->length + 1);
if (!result) return JS_EXCEPTION;
int exact = (int)bd->length;
JSText *pt = pretext_init (ctx, exact);
if (!pt) return JS_EXCEPTION;
bd = (JSBlob *)chase (argv[0]);
data = (const uint8_t *)bd->bits;
for (size_t i = 0; i < (size_t)bd->length; i++) {
size_t byte_idx = i / 8;
size_t bit_idx = i % 8;
result[i] = (data[byte_idx] & (1u << bit_idx)) ? '1' : '0';
string_put (pt, (int)i,
(data[byte_idx] & (1u << bit_idx)) ? '1' : '0');
}
result[bd->length] = '\0';
JSValue ret = JS_NewString (ctx, result);
js_free (ctx, result);
return ret;
pt->length = exact;
return pretext_end (ctx, pt);
} else if (format == 'o') {
size_t octal_len = ((size_t)bd->length + 2) / 3;
char *result = js_malloc (ctx, octal_len + 1);
if (!result) return JS_EXCEPTION;
for (size_t i = 0; i < octal_len; i++) {
int exact = (int)(((size_t)bd->length + 2) / 3);
JSText *pt = pretext_init (ctx, exact);
if (!pt) return JS_EXCEPTION;
bd = (JSBlob *)chase (argv[0]);
data = (const uint8_t *)bd->bits;
for (int i = 0; i < exact; i++) {
int val = 0;
for (int j = 0; j < 3; j++) {
size_t bit_pos = i * 3 + (size_t)j;
size_t bit_pos = (size_t)i * 3 + (size_t)j;
if (bit_pos < (size_t)bd->length) {
size_t byte_idx = bit_pos / 8;
size_t bit_idx = bit_pos % 8;
if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j);
}
}
result[i] = (char)('0' + val);
string_put (pt, i, (uint32_t)('0' + val));
}
result[octal_len] = '\0';
JSValue ret = JS_NewString (ctx, result);
js_free (ctx, result);
return ret;
pt->length = exact;
return pretext_end (ctx, pt);
} else if (format == 't') {
static const char b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
size_t b32_len = ((size_t)bd->length + 4) / 5;
char *result = js_malloc (ctx, b32_len + 1);
if (!result) return JS_EXCEPTION;
for (size_t i = 0; i < b32_len; i++) {
int exact = (int)(((size_t)bd->length + 4) / 5);
JSText *pt = pretext_init (ctx, exact);
if (!pt) return JS_EXCEPTION;
bd = (JSBlob *)chase (argv[0]);
data = (const uint8_t *)bd->bits;
for (int i = 0; i < exact; i++) {
int val = 0;
for (int j = 0; j < 5; j++) {
size_t bit_pos = i * 5 + (size_t)j;
size_t bit_pos = (size_t)i * 5 + (size_t)j;
if (bit_pos < (size_t)bd->length) {
size_t byte_idx = bit_pos / 8;
size_t bit_idx = bit_pos % 8;
if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j);
}
}
result[i] = b32[val & 31];
string_put (pt, i, (uint32_t)b32[val & 31]);
}
result[b32_len] = '\0';
JSValue ret = JS_NewString (ctx, result);
js_free (ctx, result);
return ret;
pt->length = exact;
return pretext_end (ctx, pt);
} else {
if (bd->length % 8 != 0)
return JS_ThrowTypeError (ctx,
@@ -7074,32 +7052,28 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
const char *pref = "function ";
const char *suff = "() {\n [native code]\n}";
const char *name = "";
const char *name_cstr = NULL;
int nlen = 0;
if (!JS_IsNull (fn->name)) {
name_cstr = JS_ToCString (ctx, fn->name);
if (name_cstr) name = name_cstr;
if (name_cstr) nlen = (int)strlen (name_cstr);
}
size_t plen = strlen (pref);
size_t nlen = strlen (name);
size_t slen = strlen (suff);
int plen = (int)strlen (pref);
int slen = (int)strlen (suff);
char *result = js_malloc (ctx, plen + nlen + slen + 1);
if (!result) {
JSText *pt = pretext_init (ctx, plen + nlen + slen);
if (!pt) {
if (name_cstr) JS_FreeCString (ctx, name_cstr);
return JS_EXCEPTION;
}
memcpy (result, pref, plen);
memcpy (result + plen, name, nlen);
memcpy (result + plen + nlen, suff, slen + 1);
JSValue ret = JS_NewString (ctx, result);
js_free (ctx, result);
pt = pretext_puts8 (ctx, pt, pref);
if (pt && name_cstr) pt = pretext_write8 (ctx, pt, (const uint8_t *)name_cstr, nlen);
if (name_cstr) JS_FreeCString (ctx, name_cstr);
return ret;
if (pt) pt = pretext_puts8 (ctx, pt, suff);
return pretext_end (ctx, pt);
}
return JS_ToString (ctx, arg);
@@ -9059,7 +9033,6 @@ static JSValue js_cell_array_sort (JSContext *ctx, JSValue this_val, int argc, J
if (str_keys) {
for (word_t j = 0; j < i; j++)
JS_FreeCString (ctx, str_keys[j]);
js_free (ctx, str_keys);
}
JS_PopGCRef (ctx, &result_ref);
JS_PopGCRef (ctx, &arr_ref);
@@ -9375,18 +9348,13 @@ static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSV
if (len == 0)
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
JSValue *args = js_malloc (ctx, sizeof (JSValue) * len);
if (!args) return JS_EXCEPTION;
arr = JS_VALUE_GET_ARRAY (argv[1]); /* re-chase after malloc */
JSValue *args = alloca (sizeof (JSValue) * len);
for (int i = 0; i < len; i++) {
args[i] = arr->values[i];
}
JSValue result = JS_CallInternal (ctx, argv[0], JS_NULL, len, args, 0);
js_free (ctx, args);
return result;
return JS_CallInternal (ctx, argv[0], JS_NULL, len, args, 0);
}
/* ============================================================================
@@ -9444,7 +9412,9 @@ static int blob_grow (JSContext *ctx, JSValue *pblob, size_t need_bits) {
memcpy (nb->bits, old->bits, old_words * sizeof (word_t));
/* Install forward pointer at old location */
size_t old_blob_size = gc_object_size (old);
old->mist_hdr = objhdr_make_fwd (nb);
*((size_t *)((uint8_t *)old + sizeof (objhdr_t))) = old_blob_size;
/* Update caller's JSValue */
*pblob = JS_MKPTR (nb);