Merge branch 'cleanup_thinc'
This commit is contained in:
@@ -115,7 +115,7 @@ static JSValue js_miniz_compress(JSContext *js, JSValue this_val,
|
|||||||
|
|
||||||
/* ─── 2. Allocate an output buffer big enough ────────────── */
|
/* ─── 2. Allocate an output buffer big enough ────────────── */
|
||||||
mz_ulong out_len_est = mz_compressBound(in_len);
|
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 (!out_buf) {
|
||||||
if (cstring) JS_FreeCString(js, cstring);
|
if (cstring) JS_FreeCString(js, cstring);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
@@ -130,14 +130,14 @@ static JSValue js_miniz_compress(JSContext *js, JSValue this_val,
|
|||||||
if (cstring) JS_FreeCString(js, cstring);
|
if (cstring) JS_FreeCString(js, cstring);
|
||||||
|
|
||||||
if (st != MZ_OK) {
|
if (st != MZ_OK) {
|
||||||
js_free(js, out_buf);
|
js_free_rt(out_buf);
|
||||||
return JS_RaiseDisrupt(js,
|
return JS_RaiseDisrupt(js,
|
||||||
"miniz: compression failed (%d)", st);
|
"miniz: compression failed (%d)", st);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── 4. Hand JavaScript a copy of the compressed data ────── */
|
/* ─── 4. Hand JavaScript a copy of the compressed data ────── */
|
||||||
JSValue abuf = js_new_blob_stoned_copy(js, out_buf, out_len);
|
JSValue abuf = js_new_blob_stoned_copy(js, out_buf, out_len);
|
||||||
js_free(js, out_buf);
|
js_free_rt(out_buf);
|
||||||
return abuf;
|
return abuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ static void encode_js_object(json_encoder *enc, JSContext *js, JSValue obj) {
|
|||||||
JS_FreeCString(js, key);
|
JS_FreeCString(js, key);
|
||||||
JS_FreeAtom(js, props[i].atom);
|
JS_FreeAtom(js, props[i].atom);
|
||||||
}
|
}
|
||||||
js_free(js, props);
|
js_free_rt(props);
|
||||||
}
|
}
|
||||||
enc->endTable(enc);
|
enc->endTable(enc);
|
||||||
}
|
}
|
||||||
|
|||||||
39
qop.c
39
qop.c
@@ -84,11 +84,11 @@ static qop_desc *js2qop(JSContext *js, JSValue v) {
|
|||||||
|
|
||||||
static int js_qop_ensure_index(JSContext *js, qop_desc *qop) {
|
static int js_qop_ensure_index(JSContext *js, qop_desc *qop) {
|
||||||
if (qop->hashmap != NULL) return 1;
|
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;
|
if (!buffer) return 0;
|
||||||
int num = qop_read_index(qop, buffer);
|
int num = qop_read_index(qop, buffer);
|
||||||
if (num == 0) {
|
if (num == 0) {
|
||||||
js_free(js, buffer);
|
js_free_rt(buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -102,14 +102,14 @@ JSC_CCALL(qop_open,
|
|||||||
else if (!data)
|
else if (!data)
|
||||||
ret = JS_RaiseDisrupt(js, "Empty blob");
|
ret = JS_RaiseDisrupt(js, "Empty blob");
|
||||||
else {
|
else {
|
||||||
qop_desc *qop = js_malloc(js, sizeof(qop_desc));
|
qop_desc *qop = js_malloc_rt(sizeof(qop_desc));
|
||||||
if (!qop)
|
if (!qop)
|
||||||
ret = JS_RaiseOOM(js);
|
ret = JS_RaiseOOM(js);
|
||||||
else {
|
else {
|
||||||
int size = qop_open_data((const unsigned char *)data, len, qop);
|
int size = qop_open_data((const unsigned char *)data, len, qop);
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
js_free(js, qop);
|
js_free_rt(qop);
|
||||||
ret = JS_RaiseDisrupt(js, "Failed to open QOP archive from blob");
|
ret = JS_ThrowReferenceError(js, "Failed to open QOP archive from blob");
|
||||||
} else {
|
} else {
|
||||||
JSValue obj = JS_NewObjectClass(js, js_qop_archive_class_id);
|
JSValue obj = JS_NewObjectClass(js, js_qop_archive_class_id);
|
||||||
JS_SetOpaque(obj, qop);
|
JS_SetOpaque(obj, qop);
|
||||||
@@ -127,7 +127,7 @@ JSC_CCALL(qop_write,
|
|||||||
JS_FreeCString(js, path);
|
JS_FreeCString(js, path);
|
||||||
if (!fh) return JS_RaiseDisrupt(js, "Could not open file for writing");
|
if (!fh) return JS_RaiseDisrupt(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) {
|
if (!w) {
|
||||||
fclose(fh);
|
fclose(fh);
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
@@ -137,10 +137,10 @@ JSC_CCALL(qop_write,
|
|||||||
w->capacity = 1024;
|
w->capacity = 1024;
|
||||||
w->len = 0;
|
w->len = 0;
|
||||||
w->size = 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) {
|
if (!w->files) {
|
||||||
fclose(fh);
|
fclose(fh);
|
||||||
js_free(js, w);
|
js_free_rt(w);
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,18 +183,18 @@ static JSValue js_qop_read(JSContext *js, JSValue self, int argc, JSValue *argv)
|
|||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *dest = js_malloc(js, file->size);
|
unsigned char *dest = js_malloc_rt(file->size);
|
||||||
if (!dest)
|
if (!dest)
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
|
|
||||||
int bytes = qop_read(qop, file, dest);
|
int bytes = qop_read(qop, file, dest);
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
js_free(js, dest);
|
js_free_rt(dest);
|
||||||
return JS_RaiseDisrupt(js, "Failed to read file");
|
return JS_RaiseDisrupt(js, "Failed to read file");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
|
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
|
||||||
js_free(js, dest);
|
js_free_rt(dest);
|
||||||
return blob;
|
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)
|
if (JS_ToUint32(js, &start, argv[1]) < 0 || JS_ToUint32(js, &len, argv[2]) < 0)
|
||||||
return JS_RaiseDisrupt(js, "Invalid start or len");
|
return JS_RaiseDisrupt(js, "Invalid start or len");
|
||||||
|
|
||||||
unsigned char *dest = js_malloc(js, len);
|
unsigned char *dest = js_malloc_rt(len);
|
||||||
if (!dest)
|
if (!dest)
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
|
|
||||||
int bytes = qop_read_ex(qop, file, dest, start, len);
|
int bytes = qop_read_ex(qop, file, dest, start, len);
|
||||||
if (bytes == 0) {
|
if (bytes == 0) {
|
||||||
js_free(js, dest);
|
js_free_rt(dest);
|
||||||
return JS_RaiseDisrupt(js, "Failed to read file part");
|
return JS_RaiseDisrupt(js, "Failed to read file part");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
|
JSValue blob = js_new_blob_stoned_copy(js, dest, bytes);
|
||||||
js_free(js, dest);
|
js_free_rt(dest);
|
||||||
return blob;
|
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];
|
qop_file *file = &qop->hashmap[i];
|
||||||
if (file->size == 0) continue; // empty slot
|
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) {
|
if (!path) {
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = qop_read_path(qop, file, path);
|
int len = qop_read_path(qop, file, path);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
js_free(js, path);
|
js_free_rt(path);
|
||||||
continue; // skip on error
|
continue; // skip on error
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue str = JS_NewStringLen(js, path, len - 1); // -1 for null terminator
|
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);
|
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 + "/"
|
// Check if any file starts with path + "/"
|
||||||
size_t path_len = strlen(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);
|
memcpy(prefix, path, path_len);
|
||||||
prefix[path_len] = '/';
|
prefix[path_len] = '/';
|
||||||
prefix[path_len + 1] = '\0';
|
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);
|
JS_FreeCString(js, path);
|
||||||
return JS_NewBool(js, found);
|
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) {
|
if (w->len >= w->capacity) {
|
||||||
w->capacity *= 2;
|
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) {
|
if (!new_files) {
|
||||||
JS_FreeCString(js, path);
|
JS_FreeCString(js, path);
|
||||||
return JS_RaiseOOM(js);
|
return JS_RaiseOOM(js);
|
||||||
|
|||||||
@@ -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
|
/* JS_IsPretext, JS_KeyGetStr, JS_PushGCRef, JS_PopGCRef, JS_AddGCRef, JS_DeleteGCRef
|
||||||
are defined after JSContext (they need its fields) */
|
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 */
|
/* Forward declaration for string_get */
|
||||||
static inline int string_get (const JSText *p, int idx);
|
static inline int string_get (const JSText *p, int idx);
|
||||||
@@ -899,8 +897,9 @@ typedef struct JSBlob {
|
|||||||
} JSBlob;
|
} JSBlob;
|
||||||
|
|
||||||
typedef struct JSText {
|
typedef struct JSText {
|
||||||
objhdr_t hdr; /* mist header */
|
objhdr_t hdr; /* mist header — cap56 = allocated capacity */
|
||||||
word_t length; /* length (or hash for stoned text) */
|
word_t length; /* character count (always) */
|
||||||
|
word_t hash; /* cached hash (stoned text only) */
|
||||||
word_t packed[]; /* two chars per packed word */
|
word_t packed[]; /* two chars per packed word */
|
||||||
} JSText;
|
} JSText;
|
||||||
|
|
||||||
@@ -1022,7 +1021,6 @@ static inline uint64_t fash64_hash_one (uint64_t word) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline word_t JSText_len (const JSText *text) {
|
static inline word_t JSText_len (const JSText *text) {
|
||||||
if (objhdr_s (text->hdr)) return objhdr_cap56 (text->hdr);
|
|
||||||
return text->length;
|
return text->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1568,7 +1566,6 @@ JSText *pretext_putc (JSContext *ctx, JSText *s, uint32_t c);
|
|||||||
JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v);
|
JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v);
|
||||||
JSValue js_new_blob (JSContext *ctx, blob *b);
|
JSValue js_new_blob (JSContext *ctx, blob *b);
|
||||||
/* Functions from header region (defined in runtime.c) */
|
/* 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_alloc (JSContext *ctx, size_t bytes, size_t align);
|
||||||
void ct_free_all (JSContext *ctx);
|
void ct_free_all (JSContext *ctx);
|
||||||
int ct_resize (JSContext *ctx);
|
int ct_resize (JSContext *ctx);
|
||||||
@@ -1620,13 +1617,6 @@ static inline int to_digit (int c) {
|
|||||||
else return 36;
|
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);
|
JSText *js_alloc_string (JSContext *ctx, int max_len);
|
||||||
JSValue js_key_from_string (JSContext *ctx, JSValue val);
|
JSValue js_key_from_string (JSContext *ctx, JSValue val);
|
||||||
|
|||||||
@@ -1015,9 +1015,6 @@ void *js_debugger_val_address (JSContext *js, JSValue val);
|
|||||||
============================================================ */
|
============================================================ */
|
||||||
void *js_malloc (JSContext *ctx, size_t size);
|
void *js_malloc (JSContext *ctx, size_t size);
|
||||||
void *js_mallocz (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 */
|
/* Runtime-level memory functions */
|
||||||
void *js_malloc_rt (size_t size);
|
void *js_malloc_rt (size_t size);
|
||||||
|
|||||||
432
source/runtime.c
432
source/runtime.c
@@ -110,16 +110,16 @@ JS_BOOL JS_IsFrame(JSValue v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t get_text_hash (JSText *text) {
|
uint64_t get_text_hash (JSText *text) {
|
||||||
uint64_t len = objhdr_cap56 (text->hdr);
|
uint64_t len = text->length;
|
||||||
size_t word_count = (len + 1) / 2;
|
size_t word_count = (len + 1) / 2;
|
||||||
|
|
||||||
if (objhdr_s (text->hdr)) {
|
if (objhdr_s (text->hdr)) {
|
||||||
/* Stoned text: check for cached hash */
|
/* Stoned text: check for cached hash */
|
||||||
if (text->length != 0) return text->length;
|
if (text->hash != 0) return text->hash;
|
||||||
/* Compute and cache hash using content length from header */
|
/* Compute and cache hash */
|
||||||
text->length = fash64_hash_words (text->packed, word_count, len);
|
text->hash = fash64_hash_words (text->packed, word_count, len);
|
||||||
if (!text->length) text->length = 1;
|
if (!text->hash) text->hash = 1;
|
||||||
return text->length;
|
return text->hash;
|
||||||
} else {
|
} else {
|
||||||
/* Pre-text: compute hash on the fly */
|
/* Pre-text: compute hash on the fly */
|
||||||
return fash64_hash_words (text->packed, word_count, len);
|
return fash64_hash_words (text->packed, word_count, len);
|
||||||
@@ -137,7 +137,7 @@ void pack_utf32_to_words (const uint32_t *utf32, uint32_t len, uint64_t *packed)
|
|||||||
|
|
||||||
/* Compare two packed UTF-32 texts for equality */
|
/* Compare two packed UTF-32 texts for equality */
|
||||||
int text_equal (JSText *a, const uint64_t *packed_b, uint32_t len_b) {
|
int text_equal (JSText *a, const uint64_t *packed_b, uint32_t len_b) {
|
||||||
uint32_t len_a = (uint32_t)objhdr_cap56 (a->hdr);
|
uint32_t len_a = (uint32_t)a->length;
|
||||||
if (len_a != len_b) return 0;
|
if (len_a != len_b) return 0;
|
||||||
size_t word_count = (len_a + 1) / 2;
|
size_t word_count = (len_a + 1) / 2;
|
||||||
return memcmp (a->packed, packed_b, word_count * sizeof (uint64_t)) == 0;
|
return memcmp (a->packed, packed_b, word_count * sizeof (uint64_t)) == 0;
|
||||||
@@ -291,24 +291,6 @@ int ct_resize (JSContext *ctx) {
|
|||||||
return 0;
|
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) {
|
JSValue intern_text_to_value (JSContext *ctx, const uint32_t *utf32, uint32_t len) {
|
||||||
/* Pack UTF-32 for hashing and comparison */
|
/* Pack UTF-32 for hashing and comparison */
|
||||||
@@ -349,7 +331,8 @@ JSValue intern_text_to_value (JSContext *ctx, const uint32_t *utf32, uint32_t le
|
|||||||
|
|
||||||
/* Initialize the text */
|
/* Initialize the text */
|
||||||
text->hdr = objhdr_make (len, OBJ_TEXT, false, false, false, true); /* s=1 for stoned */
|
text->hdr = objhdr_make (len, OBJ_TEXT, false, false, false, true); /* s=1 for stoned */
|
||||||
text->length = hash; /* Store hash in length field for stoned text */
|
text->length = len;
|
||||||
|
text->hash = hash;
|
||||||
memcpy (text->packed, packed, word_count * sizeof (uint64_t));
|
memcpy (text->packed, packed, word_count * sizeof (uint64_t));
|
||||||
|
|
||||||
/* Add to intern table */
|
/* Add to intern table */
|
||||||
@@ -583,6 +566,8 @@ JSValue rec_get (JSContext *ctx, JSRecord *rec, JSValue k) {
|
|||||||
return JS_NULL;
|
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) {
|
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 */
|
/* Protect the source object with a GC ref in case js_malloc triggers GC */
|
||||||
JSGCRef obj_ref;
|
JSGCRef obj_ref;
|
||||||
@@ -646,7 +631,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 */
|
/* 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);
|
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 */
|
/* Update caller's JSValue to point to new record */
|
||||||
*pobj = JS_MKPTR (new_rec);
|
*pobj = JS_MKPTR (new_rec);
|
||||||
@@ -865,11 +852,6 @@ void *js_mallocz (JSContext *ctx, size_t size) {
|
|||||||
return memset (ptr, 0, 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 */
|
/* Parser memory functions - use system allocator to avoid GC issues */
|
||||||
|
|
||||||
@@ -930,48 +912,14 @@ JSValue ppretext_end (JSContext *ctx, PPretext *p) {
|
|||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
string_put (str, i, p->data[i]);
|
string_put (str, i, p->data[i]);
|
||||||
}
|
}
|
||||||
str->hdr = objhdr_set_cap56 (str->hdr, len);
|
str->length = len;
|
||||||
|
str->hash = 0;
|
||||||
str->hdr = objhdr_set_s (str->hdr, true);
|
str->hdr = objhdr_set_s (str->hdr, true);
|
||||||
|
|
||||||
ppretext_free (p);
|
ppretext_free (p);
|
||||||
return JS_MKPTR (str);
|
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) */
|
/* Append a JSValue string to a PPretext (parser pretext) */
|
||||||
PPretext *ppretext_append_jsvalue (PPretext *p, JSValue str) {
|
PPretext *ppretext_append_jsvalue (PPretext *p, JSValue str) {
|
||||||
@@ -1386,6 +1334,7 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
|
|||||||
*to_free += size;
|
*to_free += size;
|
||||||
|
|
||||||
*hdr_ptr = objhdr_make_fwd (new_ptr);
|
*hdr_ptr = objhdr_make_fwd (new_ptr);
|
||||||
|
*((size_t *)((uint8_t *)hdr_ptr + sizeof (objhdr_t))) = size;
|
||||||
|
|
||||||
return JS_MKPTR (new_ptr);
|
return JS_MKPTR (new_ptr);
|
||||||
}
|
}
|
||||||
@@ -1735,6 +1684,70 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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) */
|
/* Return old block (in poison mode, just poison it and leak) */
|
||||||
heap_block_free (rt, from_base, old_heap_size);
|
heap_block_free (rt, from_base, old_heap_size);
|
||||||
|
|
||||||
@@ -1909,7 +1922,8 @@ JSText *js_alloc_string (JSContext *ctx, int max_len) {
|
|||||||
}
|
}
|
||||||
/* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */
|
/* Initialize objhdr_t with OBJ_TEXT type and capacity in cap56 */
|
||||||
str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false);
|
str->hdr = objhdr_make (max_len, OBJ_TEXT, false, false, false, false);
|
||||||
str->length = 0; /* length starts at 0, capacity is in hdr */
|
str->length = 0;
|
||||||
|
str->hash = 0;
|
||||||
/* Zero packed data so odd-length strings have deterministic padding.
|
/* Zero packed data so odd-length strings have deterministic padding.
|
||||||
js_malloc is a bump allocator and does not zero memory; without this,
|
js_malloc is a bump allocator and does not zero memory; without this,
|
||||||
the last word's unused low 32 bits contain garbage, causing
|
the last word's unused low 32 bits contain garbage, causing
|
||||||
@@ -2086,6 +2100,37 @@ void JS_FreeContext (JSContext *ctx) {
|
|||||||
|
|
||||||
for (i = 0; i < ctx->class_count; i++) {
|
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_array);
|
||||||
js_free_rt (ctx->class_proto);
|
js_free_rt (ctx->class_proto);
|
||||||
|
|
||||||
@@ -2457,10 +2502,7 @@ JSText *pretext_concat_value (JSContext *ctx, JSText *s, JSValue v) {
|
|||||||
JSValue pretext_end (JSContext *ctx, JSText *s) {
|
JSValue pretext_end (JSContext *ctx, JSText *s) {
|
||||||
if (!s) return JS_EXCEPTION;
|
if (!s) return JS_EXCEPTION;
|
||||||
int len = (int)s->length;
|
int len = (int)s->length;
|
||||||
if (len == 0) {
|
if (len == 0) return JS_KEY_empty;
|
||||||
js_free (ctx, s);
|
|
||||||
return JS_KEY_empty;
|
|
||||||
}
|
|
||||||
/* Promote short ASCII strings to immediate values */
|
/* Promote short ASCII strings to immediate values */
|
||||||
if (len <= MIST_ASCII_MAX_LEN) {
|
if (len <= MIST_ASCII_MAX_LEN) {
|
||||||
char buf[MIST_ASCII_MAX_LEN];
|
char buf[MIST_ASCII_MAX_LEN];
|
||||||
@@ -2475,9 +2517,8 @@ JSValue pretext_end (JSContext *ctx, JSText *s) {
|
|||||||
if (!JS_IsNull (imm)) return imm;
|
if (!JS_IsNull (imm)) return imm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Set final length in capacity field and clear length for hash storage */
|
/* length is already set by caller; cap56 stays as allocated capacity */
|
||||||
s->hdr = objhdr_set_cap56 (s->hdr, len);
|
s->hash = 0;
|
||||||
s->length = 0;
|
|
||||||
s->hdr = objhdr_set_s (s->hdr, true); /* mark as stone */
|
s->hdr = objhdr_set_s (s->hdr, true); /* mark as stone */
|
||||||
return JS_MKPTR (s);
|
return JS_MKPTR (s);
|
||||||
}
|
}
|
||||||
@@ -2960,7 +3001,9 @@ static int js_array_grow (JSContext *ctx, JSValue *arr_ptr, word_t min_cap) {
|
|||||||
new_arr->values[i] = JS_NULL;
|
new_arr->values[i] = JS_NULL;
|
||||||
|
|
||||||
/* Install forward header at old location */
|
/* Install forward header at old location */
|
||||||
|
size_t old_arr_size = gc_object_size (arr);
|
||||||
arr->mist_hdr = objhdr_make_fwd (new_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 */
|
/* Update the tracked JSValue to point to new array */
|
||||||
*arr_ptr = JS_MKPTR (new_arr);
|
*arr_ptr = JS_MKPTR (new_arr);
|
||||||
@@ -4149,25 +4192,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) {
|
static JSValue js_dtoa2 (JSContext *ctx, double d, int radix, int n_digits, int flags) {
|
||||||
char static_buf[128], *buf, *tmp_buf;
|
char buf[1088];
|
||||||
int len, len_max;
|
|
||||||
JSValue res;
|
|
||||||
JSDTOATempMem dtoa_mem;
|
JSDTOATempMem dtoa_mem;
|
||||||
len_max = js_dtoa_max_len (d, radix, n_digits, flags);
|
int len = js_dtoa (buf, d, radix, n_digits, flags, &dtoa_mem);
|
||||||
|
return js_new_string8_len (ctx, buf, len);
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue JS_ToString (JSContext *ctx, JSValue val) {
|
JSValue JS_ToString (JSContext *ctx, JSValue val) {
|
||||||
@@ -5010,7 +5038,7 @@ JSValue js_compile_regexp (JSContext *ctx, JSValue pattern, JSValue flags) {
|
|||||||
|
|
||||||
ret
|
ret
|
||||||
= js_new_string8_len (ctx, (const char *)re_bytecode_buf, re_bytecode_len);
|
= 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5365,8 +5393,8 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
}
|
}
|
||||||
for (int ci = 0; ci < imm_len; ci++)
|
for (int ci = 0; ci < imm_len; ci++)
|
||||||
string_put (hs, ci, MIST_GetImmediateASCIIChar (str_ref.val, ci));
|
string_put (hs, ci, MIST_GetImmediateASCIIChar (str_ref.val, ci));
|
||||||
hs->hdr = objhdr_set_cap56 (hs->hdr, imm_len);
|
hs->length = imm_len;
|
||||||
hs->length = 0;
|
hs->hash = 0;
|
||||||
hs->hdr = objhdr_set_s (hs->hdr, true);
|
hs->hdr = objhdr_set_s (hs->hdr, true);
|
||||||
str_ref.val = JS_MKPTR (hs);
|
str_ref.val = JS_MKPTR (hs);
|
||||||
}
|
}
|
||||||
@@ -6118,12 +6146,7 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *clean = js_malloc (ctx, strlen (str) + 1);
|
char *clean = alloca (strlen (str) + 1);
|
||||||
if (!clean) {
|
|
||||||
JS_FreeCString (ctx, format);
|
|
||||||
JS_FreeCString (ctx, str);
|
|
||||||
return JS_EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *p = str;
|
const char *p = str;
|
||||||
char *q = clean;
|
char *q = clean;
|
||||||
@@ -6164,7 +6187,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
*q = '\0';
|
*q = '\0';
|
||||||
char *endptr;
|
char *endptr;
|
||||||
long long n = strtoll (str, &endptr, 2);
|
long long n = strtoll (str, &endptr, 2);
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
JS_FreeCString (ctx, str);
|
JS_FreeCString (ctx, str);
|
||||||
if (endptr == str) return JS_NULL;
|
if (endptr == str) return JS_NULL;
|
||||||
@@ -6173,7 +6195,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
*q = '\0';
|
*q = '\0';
|
||||||
char *endptr;
|
char *endptr;
|
||||||
long long n = strtoll (str, &endptr, 8);
|
long long n = strtoll (str, &endptr, 8);
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
JS_FreeCString (ctx, str);
|
JS_FreeCString (ctx, str);
|
||||||
if (endptr == str) return JS_NULL;
|
if (endptr == str) return JS_NULL;
|
||||||
@@ -6182,7 +6203,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
*q = '\0';
|
*q = '\0';
|
||||||
char *endptr;
|
char *endptr;
|
||||||
long long n = strtoll (str, &endptr, 16);
|
long long n = strtoll (str, &endptr, 16);
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
JS_FreeCString (ctx, str);
|
JS_FreeCString (ctx, str);
|
||||||
if (endptr == str) return JS_NULL;
|
if (endptr == str) return JS_NULL;
|
||||||
@@ -6191,14 +6211,12 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
*q = '\0';
|
*q = '\0';
|
||||||
char *endptr;
|
char *endptr;
|
||||||
long long n = strtoll (str, &endptr, 32);
|
long long n = strtoll (str, &endptr, 32);
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
JS_FreeCString (ctx, str);
|
JS_FreeCString (ctx, str);
|
||||||
if (endptr == str) return JS_NULL;
|
if (endptr == str) return JS_NULL;
|
||||||
return JS_NewInt64 (ctx, n);
|
return JS_NewInt64 (ctx, n);
|
||||||
} else if (strcmp (format, "j") == 0) {
|
} else if (strcmp (format, "j") == 0) {
|
||||||
/* JavaScript style prefix */
|
/* JavaScript style prefix */
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
int radix = 10;
|
int radix = 10;
|
||||||
const char *start = str;
|
const char *start = str;
|
||||||
@@ -6230,7 +6248,6 @@ static JSValue js_cell_number (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
*q = '\0';
|
*q = '\0';
|
||||||
|
|
||||||
double d = strtod (clean, NULL);
|
double d = strtod (clean, NULL);
|
||||||
js_free (ctx, clean);
|
|
||||||
JS_FreeCString (ctx, format);
|
JS_FreeCString (ctx, format);
|
||||||
JS_FreeCString (ctx, str);
|
JS_FreeCString (ctx, str);
|
||||||
if (isnan (d)) return JS_NULL;
|
if (isnan (d)) return JS_NULL;
|
||||||
@@ -6433,13 +6450,9 @@ static JSValue js_cell_number_to_radix_string (JSContext *ctx, double num, int r
|
|||||||
return JS_NewString (ctx, result);
|
return JS_NewString (ctx, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper: add separator every n digits from right */
|
/* Helper: add separator every n digits from right, returns JSValue string */
|
||||||
static char *add_separator (JSContext *ctx, const char *str, char sep, int n) {
|
static JSValue add_separator (JSContext *ctx, const char *str, char sep, int n, int prepend_neg) {
|
||||||
if (n <= 0) {
|
if (n <= 0) return JS_NewString (ctx, str);
|
||||||
char *result = js_malloc (ctx, strlen (str) + 1);
|
|
||||||
if (result) strcpy (result, str);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int negative = (str[0] == '-');
|
int negative = (str[0] == '-');
|
||||||
const char *start = negative ? str + 1 : str;
|
const char *start = negative ? str + 1 : str;
|
||||||
@@ -6447,34 +6460,35 @@ static char *add_separator (JSContext *ctx, const char *str, char sep, int n) {
|
|||||||
/* Find decimal point */
|
/* Find decimal point */
|
||||||
const char *decimal = strchr (start, '.');
|
const char *decimal = strchr (start, '.');
|
||||||
int int_len = decimal ? (int)(decimal - start) : (int)strlen (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 num_seps = (int_len - 1) / n;
|
||||||
int result_len = strlen (str) + num_seps + 1;
|
int total = (negative ? 1 : 0) + prepend_neg + int_len + num_seps + dec_len;
|
||||||
char *result = js_malloc (ctx, result_len);
|
|
||||||
if (!result) return NULL;
|
|
||||||
|
|
||||||
char *q = result;
|
JSText *pt = pretext_init (ctx, total);
|
||||||
if (negative) *q++ = '-';
|
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;
|
int count = int_len % n;
|
||||||
if (count == 0) count = n;
|
if (count == 0) count = n;
|
||||||
|
|
||||||
for (int i = 0; i < int_len; i++) {
|
for (int i = 0; i < int_len; i++) {
|
||||||
if (i > 0 && count == 0) {
|
if (i > 0 && count == 0) {
|
||||||
*q++ = sep;
|
string_put (pt, pos++, (uint32_t)sep);
|
||||||
count = n;
|
count = n;
|
||||||
}
|
}
|
||||||
*q++ = start[i];
|
string_put (pt, pos++, (uint32_t)(unsigned char)start[i]);
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decimal) {
|
for (int i = 0; i < dec_len; i++)
|
||||||
strcpy (q, decimal);
|
string_put (pt, pos++, (uint32_t)(unsigned char)decimal[i]);
|
||||||
} else {
|
|
||||||
*q = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
pt->length = pos;
|
||||||
|
return pretext_end (ctx, pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper: format number with format string */
|
/* Helper: format number with format string */
|
||||||
@@ -6512,7 +6526,6 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
|
|||||||
if (format[i] != '\0') return JS_NULL;
|
if (format[i] != '\0') return JS_NULL;
|
||||||
|
|
||||||
char buf[128];
|
char buf[128];
|
||||||
char *result_str = NULL;
|
|
||||||
|
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case 'e': {
|
case 'e': {
|
||||||
@@ -6538,22 +6551,13 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
|
|||||||
/* Space separated */
|
/* Space separated */
|
||||||
if (separation == 0) separation = 3;
|
if (separation == 0) separation = 3;
|
||||||
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
||||||
result_str = add_separator (ctx, buf, ' ', separation);
|
return add_separator (ctx, buf, ' ', separation, 0);
|
||||||
if (!result_str) return JS_EXCEPTION;
|
|
||||||
JSValue ret = JS_NewString (ctx, result_str);
|
|
||||||
js_free (ctx, result_str);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
case 'u': {
|
case 'u': {
|
||||||
/* Underbar separated */
|
/* Underbar separated */
|
||||||
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
||||||
if (separation > 0) {
|
if (separation > 0)
|
||||||
result_str = add_separator (ctx, buf, '_', separation);
|
return add_separator (ctx, buf, '_', separation, 0);
|
||||||
if (!result_str) return JS_EXCEPTION;
|
|
||||||
JSValue ret = JS_NewString (ctx, result_str);
|
|
||||||
js_free (ctx, result_str);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return JS_NewString (ctx, buf);
|
return JS_NewString (ctx, buf);
|
||||||
}
|
}
|
||||||
case 'd':
|
case 'd':
|
||||||
@@ -6562,11 +6566,7 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
|
|||||||
if (separation == 0) separation = 3;
|
if (separation == 0) separation = 3;
|
||||||
if (places == 0 && style == 'd') places = 2;
|
if (places == 0 && style == 'd') places = 2;
|
||||||
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
snprintf (buf, sizeof (buf), "%.*f", places, num);
|
||||||
result_str = add_separator (ctx, buf, ',', separation);
|
return add_separator (ctx, buf, ',', separation, 0);
|
||||||
if (!result_str) return JS_EXCEPTION;
|
|
||||||
JSValue ret = JS_NewString (ctx, result_str);
|
|
||||||
js_free (ctx, result_str);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
case 'v': {
|
case 'v': {
|
||||||
/* European style: comma decimal, period separator */
|
/* European style: comma decimal, period separator */
|
||||||
@@ -6575,13 +6575,8 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
|
|||||||
for (char *p = buf; *p; p++) {
|
for (char *p = buf; *p; p++) {
|
||||||
if (*p == '.') *p = ',';
|
if (*p == '.') *p = ',';
|
||||||
}
|
}
|
||||||
if (separation > 0) {
|
if (separation > 0)
|
||||||
result_str = add_separator (ctx, buf, '.', separation);
|
return add_separator (ctx, buf, '.', separation, 0);
|
||||||
if (!result_str) return JS_EXCEPTION;
|
|
||||||
JSValue ret = JS_NewString (ctx, result_str);
|
|
||||||
js_free (ctx, result_str);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return JS_NewString (ctx, buf);
|
return JS_NewString (ctx, buf);
|
||||||
}
|
}
|
||||||
case 'i': {
|
case 'i': {
|
||||||
@@ -6597,26 +6592,8 @@ static JSValue js_cell_format_number (JSContext *ctx, double num, const char *fo
|
|||||||
memmove (buf + (places - len), buf, len + 1);
|
memmove (buf + (places - len), buf, len + 1);
|
||||||
memset (buf, '0', places - len);
|
memset (buf, '0', places - len);
|
||||||
}
|
}
|
||||||
if (separation > 0) {
|
if (separation > 0)
|
||||||
result_str = add_separator (ctx, buf, '_', separation);
|
return add_separator (ctx, buf, '_', separation, neg);
|
||||||
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 (neg) {
|
if (neg) {
|
||||||
memmove (buf + 1, buf, strlen (buf) + 1);
|
memmove (buf + 1, buf, strlen (buf) + 1);
|
||||||
buf[0] = '-';
|
buf[0] = '-';
|
||||||
@@ -6838,69 +6815,72 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
|
|
||||||
if (format == 'h') {
|
if (format == 'h') {
|
||||||
static const char hex[] = "0123456789abcdef";
|
static const char hex[] = "0123456789abcdef";
|
||||||
char *result = js_malloc (ctx, byte_len * 2 + 1);
|
int exact = (int)(byte_len * 2);
|
||||||
if (!result) return JS_EXCEPTION;
|
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++) {
|
for (size_t i = 0; i < byte_len; i++) {
|
||||||
result[i * 2] = hex[(data[i] >> 4) & 0xF];
|
string_put (pt, (int)(i * 2), (uint32_t)hex[(data[i] >> 4) & 0xF]);
|
||||||
result[i * 2 + 1] = hex[data[i] & 0xF];
|
string_put (pt, (int)(i * 2 + 1), (uint32_t)hex[data[i] & 0xF]);
|
||||||
}
|
}
|
||||||
result[byte_len * 2] = '\0';
|
pt->length = exact;
|
||||||
JSValue ret = JS_NewString (ctx, result);
|
return pretext_end (ctx, pt);
|
||||||
js_free (ctx, result);
|
|
||||||
return ret;
|
|
||||||
} else if (format == 'b') {
|
} else if (format == 'b') {
|
||||||
char *result = js_malloc (ctx, bd->length + 1);
|
int exact = (int)bd->length;
|
||||||
if (!result) return JS_EXCEPTION;
|
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++) {
|
for (size_t i = 0; i < (size_t)bd->length; i++) {
|
||||||
size_t byte_idx = i / 8;
|
size_t byte_idx = i / 8;
|
||||||
size_t bit_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';
|
pt->length = exact;
|
||||||
JSValue ret = JS_NewString (ctx, result);
|
return pretext_end (ctx, pt);
|
||||||
js_free (ctx, result);
|
|
||||||
return ret;
|
|
||||||
} else if (format == 'o') {
|
} else if (format == 'o') {
|
||||||
size_t octal_len = ((size_t)bd->length + 2) / 3;
|
int exact = (int)(((size_t)bd->length + 2) / 3);
|
||||||
char *result = js_malloc (ctx, octal_len + 1);
|
JSText *pt = pretext_init (ctx, exact);
|
||||||
if (!result) return JS_EXCEPTION;
|
if (!pt) return JS_EXCEPTION;
|
||||||
for (size_t i = 0; i < octal_len; i++) {
|
bd = (JSBlob *)chase (argv[0]);
|
||||||
|
data = (const uint8_t *)bd->bits;
|
||||||
|
for (int i = 0; i < exact; i++) {
|
||||||
int val = 0;
|
int val = 0;
|
||||||
for (int j = 0; j < 3; j++) {
|
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) {
|
if (bit_pos < (size_t)bd->length) {
|
||||||
size_t byte_idx = bit_pos / 8;
|
size_t byte_idx = bit_pos / 8;
|
||||||
size_t bit_idx = bit_pos % 8;
|
size_t bit_idx = bit_pos % 8;
|
||||||
if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j);
|
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';
|
pt->length = exact;
|
||||||
JSValue ret = JS_NewString (ctx, result);
|
return pretext_end (ctx, pt);
|
||||||
js_free (ctx, result);
|
|
||||||
return ret;
|
|
||||||
} else if (format == 't') {
|
} else if (format == 't') {
|
||||||
static const char b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
static const char b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||||
size_t b32_len = ((size_t)bd->length + 4) / 5;
|
int exact = (int)(((size_t)bd->length + 4) / 5);
|
||||||
char *result = js_malloc (ctx, b32_len + 1);
|
JSText *pt = pretext_init (ctx, exact);
|
||||||
if (!result) return JS_EXCEPTION;
|
if (!pt) return JS_EXCEPTION;
|
||||||
for (size_t i = 0; i < b32_len; i++) {
|
bd = (JSBlob *)chase (argv[0]);
|
||||||
|
data = (const uint8_t *)bd->bits;
|
||||||
|
for (int i = 0; i < exact; i++) {
|
||||||
int val = 0;
|
int val = 0;
|
||||||
for (int j = 0; j < 5; j++) {
|
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) {
|
if (bit_pos < (size_t)bd->length) {
|
||||||
size_t byte_idx = bit_pos / 8;
|
size_t byte_idx = bit_pos / 8;
|
||||||
size_t bit_idx = bit_pos % 8;
|
size_t bit_idx = bit_pos % 8;
|
||||||
if (data[byte_idx] & (1u << bit_idx)) val |= (1 << j);
|
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';
|
pt->length = exact;
|
||||||
JSValue ret = JS_NewString (ctx, result);
|
return pretext_end (ctx, pt);
|
||||||
js_free (ctx, result);
|
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
if (bd->length % 8 != 0)
|
if (bd->length % 8 != 0)
|
||||||
return JS_RaiseDisrupt (ctx,
|
return JS_RaiseDisrupt (ctx,
|
||||||
@@ -7010,32 +6990,28 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
|
|
||||||
const char *pref = "function ";
|
const char *pref = "function ";
|
||||||
const char *suff = "() {\n [native code]\n}";
|
const char *suff = "() {\n [native code]\n}";
|
||||||
const char *name = "";
|
|
||||||
const char *name_cstr = NULL;
|
const char *name_cstr = NULL;
|
||||||
|
int nlen = 0;
|
||||||
|
|
||||||
if (!JS_IsNull (fn->name)) {
|
if (!JS_IsNull (fn->name)) {
|
||||||
name_cstr = JS_ToCString (ctx, 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);
|
int plen = (int)strlen (pref);
|
||||||
size_t nlen = strlen (name);
|
int slen = (int)strlen (suff);
|
||||||
size_t slen = strlen (suff);
|
|
||||||
|
|
||||||
char *result = js_malloc (ctx, plen + nlen + slen + 1);
|
JSText *pt = pretext_init (ctx, plen + nlen + slen);
|
||||||
if (!result) {
|
if (!pt) {
|
||||||
if (name_cstr) JS_FreeCString (ctx, name_cstr);
|
if (name_cstr) JS_FreeCString (ctx, name_cstr);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy (result, pref, plen);
|
pt = pretext_puts8 (ctx, pt, pref);
|
||||||
memcpy (result + plen, name, nlen);
|
if (pt && name_cstr) pt = pretext_write8 (ctx, pt, (const uint8_t *)name_cstr, nlen);
|
||||||
memcpy (result + plen + nlen, suff, slen + 1);
|
|
||||||
|
|
||||||
JSValue ret = JS_NewString (ctx, result);
|
|
||||||
js_free (ctx, result);
|
|
||||||
if (name_cstr) JS_FreeCString (ctx, name_cstr);
|
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);
|
return JS_ToString (ctx, arg);
|
||||||
@@ -8995,7 +8971,6 @@ static JSValue js_cell_array_sort (JSContext *ctx, JSValue this_val, int argc, J
|
|||||||
if (str_keys) {
|
if (str_keys) {
|
||||||
for (word_t j = 0; j < i; j++)
|
for (word_t j = 0; j < i; j++)
|
||||||
JS_FreeCString (ctx, str_keys[j]);
|
JS_FreeCString (ctx, str_keys[j]);
|
||||||
js_free (ctx, str_keys);
|
|
||||||
}
|
}
|
||||||
JS_PopGCRef (ctx, &result_ref);
|
JS_PopGCRef (ctx, &result_ref);
|
||||||
JS_PopGCRef (ctx, &arr_ref);
|
JS_PopGCRef (ctx, &arr_ref);
|
||||||
@@ -9311,18 +9286,13 @@ static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSV
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||||
|
|
||||||
JSValue *args = js_malloc (ctx, sizeof (JSValue) * len);
|
JSValue *args = alloca (sizeof (JSValue) * len);
|
||||||
if (!args) return JS_EXCEPTION;
|
|
||||||
arr = JS_VALUE_GET_ARRAY (argv[1]); /* re-chase after malloc */
|
|
||||||
|
|
||||||
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, argv[0], JS_NULL, len, args, 0);
|
return JS_CallInternal (ctx, argv[0], JS_NULL, len, args, 0);
|
||||||
|
|
||||||
js_free (ctx, args);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
@@ -9380,7 +9350,9 @@ static int blob_grow (JSContext *ctx, JSValue *pblob, size_t need_bits) {
|
|||||||
memcpy (nb->bits, old->bits, old_words * sizeof (word_t));
|
memcpy (nb->bits, old->bits, old_words * sizeof (word_t));
|
||||||
|
|
||||||
/* Install forward pointer at old location */
|
/* Install forward pointer at old location */
|
||||||
|
size_t old_blob_size = gc_object_size (old);
|
||||||
old->mist_hdr = objhdr_make_fwd (nb);
|
old->mist_hdr = objhdr_make_fwd (nb);
|
||||||
|
*((size_t *)((uint8_t *)old + sizeof (objhdr_t))) = old_blob_size;
|
||||||
|
|
||||||
/* Update caller's JSValue */
|
/* Update caller's JSValue */
|
||||||
*pblob = JS_MKPTR (nb);
|
*pblob = JS_MKPTR (nb);
|
||||||
|
|||||||
Reference in New Issue
Block a user