MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add proper gc, dynamic memory allocation

+106 -7
+4 -1
include/ant.h
··· 13 13 }; 14 14 15 15 struct js *js_create(void *buf, size_t len); 16 - const char *js_str(struct js *, jsval_t val); 16 + struct js *js_create_dynamic(size_t initial_size, size_t max_size); 17 + void js_destroy(struct js *); 17 18 18 19 jsval_t js_glob(struct js *); 19 20 jsval_t js_eval(struct js *, const char *, size_t); ··· 53 54 54 55 double js_getnum(jsval_t val); 55 56 char *js_getstr(struct js *js, jsval_t val, size_t *len); 57 + 58 + const char *js_str(struct js *, jsval_t val); 56 59 57 60 typedef struct { 58 61 jsval_t obj;
+1 -1
meson.build
··· 41 41 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 42 42 43 43 version_conf = configuration_data() 44 - version_conf.set('ANT_VERSION', '0.0.5.52') 44 + version_conf.set('ANT_VERSION', '0.0.5.53') 45 45 version_conf.set('ANT_GIT_HASH', git_hash) 46 46 version_conf.set('ANT_BUILD_DATE', build_date) 47 47
+83 -2
src/ant.c
··· 103 103 void *cstk; // C stack pointer at the beginning of js_eval() 104 104 jsval_t current_func; // currently executing function (for native closures) 105 105 bool var_warning_shown; // flag to show var deprecation warning only once 106 + bool owns_mem; // true if js owns the memory buffer (dynamic allocation) 107 + jsoff_t max_size; // maximum allowed memory size (for dynamic growth) 106 108 }; 107 109 108 110 enum { ··· 170 172 #define CHECKV(_v) do { if (is_err(_v)) { res = (_v); goto done; } } while (0) 171 173 #define EXPECT(_tok, _e) do { if (next(js) != _tok) { _e; return js_mkerr(js, "parse error"); }; js->consumed = 1; } while (0) 172 174 175 + static void js_gc(struct js *js); 173 176 static bool streq(const char *buf, size_t len, const char *p, size_t n); 174 177 static size_t tostr(struct js *js, jsval_t value, char *buf, size_t len); 175 178 static size_t strpromise(struct js *js, jsval_t value, char *buf, size_t len); ··· 674 677 (t == T_OBJ || t == T_FUNC || t == T_ARR) || (t == T_STR && vstrlen(js, v) > 0); 675 678 } 676 679 680 + static bool js_try_grow_memory(struct js *js, size_t needed) { 681 + if (!js->owns_mem) return false; 682 + if (js->max_size == 0) return false; 683 + 684 + size_t current_total = sizeof(struct js) + js->size; 685 + size_t new_size = current_total * 2; 686 + 687 + while (new_size < current_total + needed && new_size <= (size_t)js->max_size) new_size *= 2; 688 + 689 + if (new_size > (size_t)js->max_size) new_size = (size_t)js->max_size; 690 + if (new_size <= current_total) return false; 691 + 692 + void *old_buf = (void *)((uint8_t *)js - 0); 693 + void *new_buf = realloc(old_buf, new_size); 694 + 695 + if (new_buf == NULL) return false; 696 + struct js *new_js = (struct js *)new_buf; 697 + 698 + new_js->mem = (uint8_t *)(new_js + 1); 699 + jsoff_t old_size = new_js->size; 700 + new_js->size = (jsoff_t)(new_size - sizeof(struct js)); 701 + new_js->size = new_js->size / 8U * 8U; 702 + 703 + if (old_size > 0) { 704 + new_js->gct = (new_js->size * new_js->gct) / old_size; 705 + } else { 706 + new_js->gct = new_js->size / 2; 707 + } 708 + 709 + return true; 710 + } 711 + 677 712 static jsoff_t js_alloc(struct js *js, size_t size) { 678 713 jsoff_t ofs = js->brk; 679 714 size = align32((jsoff_t) size); 680 - if (js->brk + size > js->size) return ~(jsoff_t) 0; 715 + if (js->brk + size > js->size) { 716 + if (js_try_grow_memory(js, size)) { 717 + ofs = js->brk; 718 + if (js->brk + size > js->size) return ~(jsoff_t) 0; 719 + } else { 720 + js_gc(js); 721 + ofs = js->brk; 722 + if (js->brk + size > js->size) { 723 + if (js_try_grow_memory(js, size)) { 724 + ofs = js->brk; 725 + if (js->brk + size > js->size) return ~(jsoff_t) 0; 726 + } else { 727 + return ~(jsoff_t) 0; 728 + } 729 + } 730 + } 731 + } 681 732 js->brk += (jsoff_t) size; 682 733 return ofs; 683 734 } ··· 845 896 if (js->nogc) js_unmark_entity(js, js->nogc); 846 897 } 847 898 848 - void js_gc(struct js *js) { 899 + static void js_gc(struct js *js) { 849 900 setlwm(js); 850 901 if (js->nogc == (jsoff_t) ~0) return; 851 902 js_mark_all_entities_for_deletion(js); ··· 6374 6425 6375 6426 setprop(js, glob, js_mkstr(js, "Promise", 7), mkval(T_FUNC, vdata(p_ctor_obj))); 6376 6427 6428 + js->owns_mem = false; 6429 + js->max_size = 0; 6430 + 6377 6431 return js; 6432 + } 6433 + 6434 + struct js *js_create_dynamic(size_t initial_size, size_t max_size) { 6435 + if (initial_size < sizeof(struct js) + esize(T_OBJ)) initial_size = 1024 * 1024; 6436 + if (max_size == 0 || max_size < initial_size) max_size = 512 * 1024 * 1024; 6437 + 6438 + void *buf = malloc(initial_size); 6439 + if (buf == NULL) return NULL; 6440 + 6441 + struct js *js = js_create(buf, initial_size); 6442 + if (js == NULL) { 6443 + free(buf); 6444 + return NULL; 6445 + } 6446 + 6447 + js->owns_mem = true; 6448 + js->max_size = (jsoff_t) max_size; 6449 + 6450 + return js; 6451 + } 6452 + 6453 + void js_destroy(struct js *js) { 6454 + if (js == NULL) return; 6455 + 6456 + if (js->owns_mem) { 6457 + free((void *)((uint8_t *)js - 0)); 6458 + } 6378 6459 } 6379 6460 6380 6461 double js_getnum(jsval_t value) { return tod(value); }
+18 -3
src/main.c
··· 189 189 190 190 int main(int argc, char *argv[]) { 191 191 char dump = 0; 192 - static char mem[64 * 1024 * 1024]; // 64mb 193 192 194 193 struct arg_lit *help = arg_lit0("h", "help", "display this help and exit"); 195 194 struct arg_lit *version = arg_lit0("v", "version", "display version information and exit"); 196 195 struct arg_lit *debug = arg_litn("d", "debug", 0, 10, "dump VM state (can be repeated for more detail)"); 197 196 struct arg_int *gct = arg_int0(NULL, "gct", "<threshold>", "set garbage collection threshold"); 197 + struct arg_int *initial_mem = arg_int0(NULL, "initial-mem", "<size>", "initial memory size in MB (default: 4)"); 198 + struct arg_int *max_mem = arg_int0(NULL, "max-mem", "<size>", "maximum memory size in MB (default: 512)"); 198 199 struct arg_file *file = arg_file0(NULL, NULL, "<module.js>", "JavaScript module file to execute"); 199 200 struct arg_end *end = arg_end(20); 200 201 201 - void *argtable[] = {help, version, debug, gct, file, end}; 202 + void *argtable[] = {help, version, debug, gct, initial_mem, max_mem, file, end}; 202 203 int nerrors = arg_parse(argc, argv, argtable); 203 204 204 205 if (help->count > 0) { ··· 233 234 const char *module_file = file->filename[0]; 234 235 dump = debug->count; 235 236 236 - struct js *js = js_create(mem, sizeof(mem)); 237 + size_t initial_size = 4 * 1024 * 1024; 238 + size_t max_size = 512 * 1024 * 1024; 239 + 240 + if (initial_mem->count > 0) initial_size = (size_t)initial_mem->ival[0] * 1024 * 1024; 241 + if (max_mem->count > 0) max_size = (size_t)max_mem->ival[0] * 1024 * 1024; 242 + 243 + struct js *js = js_create_dynamic(initial_size, max_size); 244 + 245 + if (js == NULL) { 246 + fprintf(stderr, "Error: Failed to allocate JavaScript runtime\n"); 247 + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); 248 + return EXIT_FAILURE; 249 + } 237 250 238 251 if (gct->count > 0) { 239 252 js_setgct(js, gct->ival[0]); ··· 273 286 } 274 287 275 288 if (dump) js_dump(js); 289 + 290 + js_destroy(js); 276 291 arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); 277 292 278 293 return result;