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 code arena allocator for code storage

+199 -128
+1
include/config.h
··· 37 37 SLOT_FIELDS, 38 38 SLOT_STRICT, 39 39 SLOT_CODE, 40 + SLOT_CODE_LEN, 40 41 SLOT_CFUNC, 41 42 SLOT_CORO, 42 43 SLOT_PROTO,
+1
include/config.h.in
··· 26 26 SLOT_FIELDS, 27 27 SLOT_STRICT, 28 28 SLOT_CODE, 29 + SLOT_CODE_LEN, 29 30 SLOT_CFUNC, 30 31 SLOT_CORO, 31 32 SLOT_PROTO,
-1
include/internal.h
··· 31 31 jsoff_t pos; // current parsing position 32 32 jsoff_t toff; // offset of the last parsed token 33 33 jsoff_t tlen; // length of the last parsed token 34 - jsoff_t nogc; // entity offset to exclude from GC 35 34 jsval_t tval; // holds last parsed numeric or string literal value 36 35 jsval_t scope; // current scope 37 36 jsval_t this_val; // 'this' value for currently executing function
+17 -6
include/runtime.h
··· 6 6 7 7 #define ANT_RUNTIME_CRYPTO_INIT (1u << 0) 8 8 #define ANT_RUNTIME_EXT_EVENT_LOOP (1u << 1) 9 + #define CODE_ARENA_BLOCK_SIZE (64 * 1024) 9 10 10 11 struct ant_runtime { 11 - struct js *js; // offset 0 12 - char **argv; // offset 8 13 - jsval_t ant_obj; // offset 16 14 - int argc; // offset 24 15 - unsigned int flags; // offset 28 16 - const char *ls_fp; // offset 32 12 + struct js *js; 13 + char **argv; 14 + jsval_t ant_obj; 15 + int argc; 16 + unsigned int flags; 17 + const char *ls_fp; 17 18 }; 18 19 20 + typedef struct code_block { 21 + struct code_block *next; 22 + size_t used; 23 + size_t capacity; 24 + char data[]; 25 + } code_block_t; 26 + 19 27 extern struct ant_runtime *const rt; 20 28 struct ant_runtime *ant_runtime_init(struct js *js, int argc, char **argv, struct arg_file *ls_p); 29 + 30 + const char *code_arena_alloc(const char *code, size_t len); 31 + void code_arena_reset(void); 21 32 22 33 #endif
+133 -119
src/ant.c
··· 117 117 struct for_let_ctx *for_let_stack; 118 118 int for_let_stack_len; 119 119 int for_let_stack_cap; 120 - UT_array *scope_stack; // coroutine's own scope stack 120 + UT_array *scope_stack; 121 121 } coroutine_t; 122 122 123 123 typedef struct { ··· 151 151 }; 152 152 153 153 static UT_array *global_scope_stack = NULL; 154 + static UT_array *saved_scope_stack = NULL; 155 + 154 156 static this_stack_t global_this_stack = {NULL, 0, 0}; 155 157 static call_stack_t global_call_stack = {NULL, 0, 0}; 156 158 static coroutine_queue_t pending_coroutines = {NULL, NULL}; ··· 2267 2269 jsval_t async_slot = get_slot(js, func_obj, SLOT_ASYNC); 2268 2270 2269 2271 bool is_async = is_true(async_slot); 2272 + bool has_code = (vtype(code_slot) == T_CFUNC); 2273 + 2270 2274 const struct func_format *fmt = &formats[is_async]; 2271 2275 2272 2276 if (vtype(builtin_slot) == T_NUM) { ··· 2279 2283 return cpy(buf, len, "[native code]", 13); 2280 2284 } 2281 2285 2282 - if (vtype(code_slot) != T_STR) { 2286 + if (!has_code) { 2283 2287 jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 2284 2288 if (vtype(cfunc_slot) == T_CFUNC) { 2285 2289 if (name && name_len > 0) { ··· 2298 2302 } 2299 2303 return cpy(buf, len, fmt->anon, fmt->anon_len); 2300 2304 } 2301 - jsval_t code_val = code_slot; 2302 2305 2303 - if (vtype(code_val) != T_STR) { 2306 + if (!has_code) { 2304 2307 if (name && name_len > 0) { 2305 2308 size_t n = cpy(buf, len, fmt->prefix, fmt->prefix_len); 2306 2309 n += cpy(buf + n, len - n, name, name_len); ··· 3382 3385 return loadval(js, off + sizeof(jsoff_t) * 2); 3383 3386 } 3384 3387 3388 + static void set_func_code_ptr(struct js *js, jsval_t func_obj, const char *code, size_t len) { 3389 + set_slot(js, func_obj, SLOT_CODE, mkval(T_CFUNC, (size_t)code)); 3390 + set_slot(js, func_obj, SLOT_CODE_LEN, tov((double)len)); 3391 + } 3392 + 3393 + static void set_func_code(struct js *js, jsval_t func_obj, const char *code, size_t len) { 3394 + const char *arena_code = code_arena_alloc(code, len); 3395 + if (!arena_code) return; 3396 + set_func_code_ptr(js, func_obj, arena_code, len); 3397 + } 3398 + 3399 + static const char *get_func_code(struct js *js, jsval_t func_obj, jsoff_t *len) { 3400 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 3401 + jsval_t len_val = get_slot(js, func_obj, SLOT_CODE_LEN); 3402 + 3403 + if (vtype(code_val) != T_CFUNC) { 3404 + if (len) *len = 0; 3405 + return NULL; 3406 + } 3407 + 3408 + if (len) *len = (jsoff_t)tod(len_val); 3409 + return (const char *)vdata(code_val); 3410 + } 3411 + 3385 3412 static inline bool is_slot_prop(jsoff_t header) { 3386 3413 return (header & SLOTMASK) != 0; 3387 3414 } ··· 6318 6345 } 6319 6346 } 6320 6347 6321 - static jsval_t call_js_internal(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope, jsval_t *bound_args, int bound_argc, jsval_t func_val) { 6322 - jsval_t saved_scope = js->scope; 6323 - jsval_t saved_this_val = js->this_val; 6348 + static inline void restore_saved_scope(struct js *js) { 6349 + if (saved_scope_stack && utarray_len(saved_scope_stack) >= 2) { 6350 + jsval_t *saved_this_ptr = (jsval_t *)utarray_back(saved_scope_stack); 6351 + js->this_val = *saved_this_ptr; 6352 + utarray_pop_back(saved_scope_stack); 6353 + 6354 + jsval_t *saved_scope_ptr = (jsval_t *)utarray_back(saved_scope_stack); 6355 + js->scope = *saved_scope_ptr; 6356 + utarray_pop_back(saved_scope_stack); 6357 + } 6358 + } 6359 + 6360 + static jsval_t call_js_internal( 6361 + struct js *js, const char *fn, jsoff_t fnlen, 6362 + jsval_t closure_scope, jsval_t *bound_args, int bound_argc, jsval_t func_val 6363 + ) { 6364 + if (saved_scope_stack == NULL) utarray_new(saved_scope_stack, &jsval_icd); 6365 + utarray_push_back(saved_scope_stack, &js->scope); 6366 + utarray_push_back(saved_scope_stack, &js->this_val); 6367 + 6324 6368 jsval_t target_this = peek_this(); 6325 6369 jsoff_t parent_scope_offset; 6326 6370 ··· 6376 6420 parsed_func_t *pf = get_or_parse_func(fn, fnlen); 6377 6421 if (!pf) { 6378 6422 utarray_free(args_arr); 6379 - js->scope = saved_scope; 6423 + restore_saved_scope(js); 6380 6424 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 6381 6425 return js_mkerr(js, "failed to parse function"); 6382 6426 } ··· 6393 6437 jsval_t r = bind_destruct_pattern(js, &fn[pp->pattern_off], pp->pattern_len, arg_val, function_scope); 6394 6438 if (is_err(r)) { 6395 6439 utarray_free(args_arr); 6396 - js->scope = saved_scope; 6440 + restore_saved_scope(js); 6397 6441 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 6398 6442 return r; 6399 6443 } ··· 6467 6511 if (global_scope_stack && utarray_len(global_scope_stack) > 0) utarray_pop_back(global_scope_stack); 6468 6512 6469 6513 utarray_free(args_arr); 6470 - js->scope = saved_scope; 6471 - js->this_val = saved_this_val; 6514 + restore_saved_scope(js); 6472 6515 return res; 6473 6516 } 6474 6517 ··· 6544 6587 return result; 6545 6588 } 6546 6589 6547 - jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 6548 - if (vtype(code_val) != T_STR) { 6590 + jsoff_t fnlen; 6591 + const char *fn = get_func_code(js, func_obj, &fnlen); 6592 + if (!fn) { 6549 6593 if (combined_args) ANT_GC_FREE(combined_args); 6550 6594 return js_mkerr(js, "function has no code"); 6551 6595 } 6552 - 6553 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 6554 - const char *fn = (const char *) (&js->mem[fnoff]); 6555 6596 6556 6597 jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 6557 6598 jsval_t saved_super = js->super_val; ··· 6743 6784 const char *code = js->code; 6744 6785 jsoff_t clen = js->clen, pos = js->pos; 6745 6786 uint8_t tok = js->tok, flags = js->flags; 6746 - jsoff_t nogc = js->nogc; 6747 6787 6748 6788 js->code = &js->code[coderefoff(args)]; 6749 6789 js->clen = codereflen(args); ··· 6753 6793 6754 6794 js->code = code; js->clen = clen; js->pos = pos; 6755 6795 js->flags = (flags & ~F_THROW) | (js->flags & F_THROW); 6756 - js->tok = tok; js->nogc = nogc; 6796 + js->tok = tok; 6757 6797 js->consumed = 1; 6758 6798 return res; 6759 6799 } ··· 6785 6825 js->code = &js->code[coderefoff(args)]; 6786 6826 js->clen = codereflen(args); 6787 6827 js->pos = skiptonext(js->code, js->clen, 0, NULL); 6828 + 6788 6829 uint8_t tok = js->tok, flags = js->flags; 6789 - jsoff_t nogc = js->nogc; 6790 6830 jsval_t res = js_mkundef(); 6791 6831 6792 6832 if (vtype(func) == T_FUNC) { ··· 6842 6882 } else { 6843 6883 jsval_t builtin_slot = get_slot(js, func_obj, SLOT_BUILTIN); 6844 6884 if (vtype(builtin_slot) == T_NUM && tod(builtin_slot) == BUILTIN_OBJECT) res = call_c(js, builtin_Object); else { 6845 - jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 6846 - if (vtype(code_val) != T_STR) return js_mkerr(js, "function has no code"); 6885 + jsoff_t fnlen; 6886 + 6887 + const char *code_str = get_func_code(js, func_obj, &fnlen); 6888 + if (!code_str) return js_mkerr(js, "function has no code"); 6889 + 6847 6890 jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 6848 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 6849 - const char *code_str = (const char *) (&js->mem[fnoff]); 6850 6891 jsval_t async_slot = get_slot(js, func_obj, SLOT_ASYNC); 6851 6892 bool is_async = vtype(async_slot) == T_BOOL && vdata(async_slot) == 1; 6852 6893 ··· 6929 6970 6930 6971 jsval_t saved_func = js->current_func; 6931 6972 js->current_func = func; 6932 - js->nogc = (jsoff_t) (fnoff - sizeof(jsoff_t)); 6933 6973 6934 6974 jsval_t saved_super = js->super_val; 6935 6975 jsval_t func_super = get_slot(js, func_obj, SLOT_SUPER); ··· 6960 7000 jsval_t fields_meta = get_slot(js, func_obj, SLOT_FIELDS); 6961 7001 if (vtype(src_val) == T_UNDEF || vtype(fields_meta) == T_UNDEF) goto skip_fields; 6962 7002 6963 - jsoff_t src_len, src_ptr_off = vstr(js, src_val, &src_len); 6964 - const char *source = (const char *)(&js->mem[src_ptr_off]); 7003 + if (vtype(src_val) != T_CFUNC) goto skip_fields; 7004 + const char *source = (const char *)vdata(src_val); 6965 7005 6966 7006 jsoff_t meta_len, meta_ptr_off = vstr(js, fields_meta, &meta_len); 6967 7007 const jsoff_t *metadata = (const jsoff_t *)(&js->mem[meta_ptr_off]); ··· 7025 7065 restore_state: 7026 7066 js->code = code, js->clen = clen, js->pos = pos; 7027 7067 js->flags = (flags & ~F_THROW) | (js->flags & F_THROW); 7028 - js->tok = tok, js->nogc = nogc; 7068 + js->tok = tok; 7029 7069 js->consumed = 1; 7030 7070 7031 7071 return res; ··· 7048 7088 result = ((jsval_t (*)(struct js *, jsval_t *, int))vdata(ts_func))(js, NULL, 0); 7049 7089 } else { 7050 7090 jsval_t func_obj = mkval(T_OBJ, vdata(ts_func)); 7051 - jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 7052 - if (vtype(code_val) != T_STR) goto restore_fallback; 7091 + jsoff_t fnlen; 7092 + const char *code_str = get_func_code(js, func_obj, &fnlen); 7093 + if (!code_str) goto restore_fallback; 7053 7094 7054 7095 jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 7055 7096 if (vtype(closure_scope) == T_UNDEF) closure_scope = js->scope; 7056 7097 7057 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 7058 - const char *code_str = (const char *)&js->mem[fnoff]; 7059 - 7060 7098 result = call_js(js, code_str, fnlen, closure_scope); 7061 7099 } 7062 7100 ··· 7095 7133 result = ((jsval_t (*)(struct js *, jsval_t *, int))vdata(fn))(js, NULL, 0); 7096 7134 } else { 7097 7135 jsval_t func_obj = mkval(T_OBJ, vdata(fn)); 7098 - jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 7099 - if (vtype(code_val) != T_STR) { js->this_val = saved; return value; } 7136 + jsoff_t fnlen; 7137 + const char *code_str = get_func_code(js, func_obj, &fnlen); 7138 + if (!code_str) { js->this_val = saved; return value; } 7100 7139 7101 7140 jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 7102 7141 if (vtype(closure_scope) == T_UNDEF) closure_scope = js->scope; 7103 7142 7104 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 7105 - result = call_js(js, (const char *)&js->mem[fnoff], fnlen, closure_scope); 7143 + result = call_js(js, code_str, fnlen, closure_scope); 7106 7144 } 7107 7145 7108 7146 js->this_val = saved; ··· 8201 8239 js->consumed = 1; 8202 8240 8203 8241 if (exe) { 8204 - jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 8205 8242 jsval_t func_obj = mkobj(js, 0); 8206 8243 if (is_err(func_obj)) return func_obj; 8207 - set_slot(js, func_obj, SLOT_CODE, str); 8244 + set_func_code(js, func_obj, &js->code[pos], js->pos - pos); 8208 8245 jsval_t name_key = js_mkstr(js, "name", 4); 8209 8246 setprop(js, func_obj, name_key, key); 8210 8247 ··· 8367 8404 return res; 8368 8405 } 8369 8406 js->flags = flags; 8370 - jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 8371 8407 js->consumed = 1; 8372 8408 jsval_t func_obj = mkobj(js, 0); 8373 8409 if (is_err(func_obj)) return func_obj; 8374 - set_slot(js, func_obj, SLOT_CODE, str); 8410 + set_func_code(js, func_obj, &js->code[pos], js->pos - pos); 8375 8411 8376 8412 jsval_t len_key = js_mkstr(js, "length", 6); 8377 8413 if (is_err(len_key)) return len_key; ··· 8549 8585 memcpy(fn_str + fn_pos, &js->code[body_start], body_len); 8550 8586 fn_pos += body_len; 8551 8587 } 8552 - jsval_t str = js_mkstr(js, fn_str, fn_pos); 8553 - free(fn_str); 8554 - if (is_err(str)) return str; 8555 8588 jsval_t func_obj = mkobj(js, 0); 8556 - if (is_err(func_obj)) return func_obj; 8557 - set_slot(js, func_obj, SLOT_CODE, str); 8589 + if (is_err(func_obj)) { free(fn_str); return func_obj; } 8590 + set_func_code(js, func_obj, fn_str, fn_pos); 8591 + free(fn_str); 8558 8592 set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 8559 8593 jsval_t async_proto = get_slot(js, js_glob(js), SLOT_ASYNC_PROTO); 8560 8594 if (vtype(async_proto) == T_FUNC) set_proto(js, func_obj, async_proto); ··· 8608 8642 if (vtype(method) != T_FUNC) return method; 8609 8643 8610 8644 jsval_t bound = mkobj(js, 0); 8611 - set_slot(js, bound, SLOT_CODE, get_slot(js, mkval(T_OBJ, vdata(method)), SLOT_CODE)); 8612 - set_slot(js, bound, SLOT_SCOPE, get_slot(js, mkval(T_OBJ, vdata(method)), SLOT_SCOPE)); 8645 + jsval_t method_obj = mkval(T_OBJ, vdata(method)); 8646 + set_slot(js, bound, SLOT_CODE, get_slot(js, method_obj, SLOT_CODE)); 8647 + set_slot(js, bound, SLOT_CODE_LEN, get_slot(js, method_obj, SLOT_CODE_LEN)); 8648 + set_slot(js, bound, SLOT_SCOPE, get_slot(js, method_obj, SLOT_SCOPE)); 8613 8649 set_slot(js, bound, SLOT_BOUND_THIS, js->this_val); 8614 8650 return mkval(T_FUNC, vdata(bound)); 8615 8651 } ··· 8697 8733 fn_pos += body_len; 8698 8734 } 8699 8735 8700 - jsval_t str = js_mkstr(js, fn_str, fn_pos); 8701 - free(fn_str); 8702 - if (is_err(str)) return str; 8703 - 8704 8736 jsval_t func_obj = mkobj(js, 0); 8705 - if (is_err(func_obj)) return func_obj; 8737 + if (is_err(func_obj)) { free(fn_str); return func_obj; } 8706 8738 8707 - set_slot(js, func_obj, SLOT_CODE, str); 8739 + set_func_code(js, func_obj, fn_str, fn_pos); 8740 + free(fn_str); 8708 8741 8709 8742 if (is_async) { 8710 8743 set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); ··· 9529 9562 fn_pos += body_len; 9530 9563 } 9531 9564 9532 - jsval_t str = js_mkstr(js, fn_str, fn_pos); 9565 + jsval_t func_obj = mkobj(js, 0); 9566 + if (is_err(func_obj)) { free(fn_str); return func_obj; } 9567 + set_func_code(js, func_obj, fn_str, fn_pos); 9533 9568 free(fn_str); 9534 - if (is_err(str)) return str; 9535 - 9536 - jsval_t func_obj = mkobj(js, 0); 9537 - if (is_err(func_obj)) return func_obj; 9538 - set_slot(js, func_obj, SLOT_CODE, str); 9539 9569 9540 9570 if (!(flags & F_NOEXEC)) { 9541 9571 jsval_t closure_scope = for_let_capture_scope(js); ··· 10096 10126 return res; 10097 10127 } 10098 10128 js->flags = flags; 10099 - jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 10100 10129 jsval_t func_obj = mkobj(js, 0); 10101 10130 if (is_err(func_obj)) return func_obj; 10102 - set_slot(js, func_obj, SLOT_CODE, str); 10131 + set_func_code(js, func_obj, &js->code[pos], js->pos - pos); 10103 10132 jsval_t len_key = js_mkstr(js, "length", 6); 10104 10133 if (is_err(len_key)) return len_key; 10105 10134 jsval_t res_len = setprop(js, func_obj, len_key, tov(param_count)); ··· 10162 10191 return res; 10163 10192 } 10164 10193 js->flags = flags; 10165 - jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 10166 10194 jsval_t func_obj = mkobj(js, 0); 10167 10195 if (is_err(func_obj)) return func_obj; 10168 - set_slot(js, func_obj, SLOT_CODE, str); 10196 + set_func_code(js, func_obj, &js->code[pos], js->pos - pos); 10169 10197 set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 10170 10198 jsval_t async_proto = get_slot(js, js_glob(js), SLOT_ASYNC_PROTO); 10171 10199 if (vtype(async_proto) == T_FUNC) set_proto(js, func_obj, async_proto); ··· 11942 11970 if (is_err(method_name)) return method_name; 11943 11971 11944 11972 jsoff_t mlen = m->fn_end - m->fn_start; 11945 - jsval_t method_code = js_mkstr(js, &js->code[m->fn_start], mlen); 11946 - if (is_err(method_code)) return method_code; 11947 11973 11948 11974 jsval_t method_obj = mkobj(js, 0); 11949 11975 if (is_err(method_obj)) return method_obj; 11950 11976 11951 - set_slot(js, method_obj, SLOT_CODE, method_code); 11977 + set_func_code(js, method_obj, &js->code[m->fn_start], mlen); 11952 11978 set_slot(js, method_obj, SLOT_SCOPE, func_scope); 11953 11979 11954 11980 if (m->is_async) { ··· 11978 12004 jsval_t func_obj = mkobj(js, 0); 11979 12005 if (is_err(func_obj)) return func_obj; 11980 12006 11981 - jsval_t ctor_str; 11982 12007 if (constructor_params_start > 0 && constructor_body_start > 0) { 11983 12008 jsoff_t code_len = constructor_body_end - constructor_params_start; 11984 - ctor_str = js_mkstr(js, &js->code[constructor_params_start], code_len); 12009 + set_func_code(js, func_obj, &js->code[constructor_params_start], code_len); 11985 12010 } else { 11986 - ctor_str = js_mkstr(js, "(){}", 4); 12011 + set_func_code_ptr(js, func_obj, "(){}", 4); 11987 12012 if (super_len > 0) set_slot(js, func_obj, SLOT_DEFAULT_CTOR, js_mktrue()); 11988 12013 } 11989 - if (is_err(ctor_str)) return ctor_str; 11990 - set_slot(js, func_obj, SLOT_CODE, ctor_str); 11991 12014 11992 12015 int instance_field_count = 0; 11993 12016 for (unsigned int i = 0; i < utarray_len(methods); i++) { ··· 12026 12049 set_slot(js, func_obj, SLOT_FIELD_COUNT, tov((double)instance_field_count)); 12027 12050 set_slot(js, func_obj, SLOT_FIELDS, fields_meta); 12028 12051 12029 - jsval_t src_ref = js_mkstr(js, js->code, js->clen); 12030 - if (is_err(src_ref)) return src_ref; 12031 - set_slot(js, func_obj, SLOT_SOURCE, src_ref); 12052 + const char *arena_src = code_arena_alloc(js->code, js->clen); 12053 + if (arena_src) set_slot(js, func_obj, SLOT_SOURCE, mkval(T_CFUNC, (size_t)arena_src)); 12032 12054 } 12033 12055 12034 12056 set_slot(js, func_obj, SLOT_SCOPE, func_scope); ··· 12079 12101 if (is_err(set_res)) return set_res; 12080 12102 } else { 12081 12103 jsoff_t mlen = m->fn_end - m->fn_start; 12082 - jsval_t method_code = js_mkstr(js, &js->code[m->fn_start], mlen); 12083 - if (is_err(method_code)) return method_code; 12084 12104 12085 12105 jsval_t method_obj = mkobj(js, 0); 12086 12106 if (is_err(method_obj)) return method_obj; 12087 12107 12088 - set_slot(js, method_obj, SLOT_CODE, method_code); 12108 + set_func_code(js, method_obj, &js->code[m->fn_start], mlen); 12089 12109 set_slot(js, method_obj, SLOT_SCOPE, func_scope); 12090 12110 if (super_len > 0) set_slot(js, method_obj, SLOT_SUPER, super_constructor); 12091 12111 ··· 12515 12535 12516 12536 static jsval_t builtin_Function(struct js *js, jsval_t *args, int nargs) { 12517 12537 if (nargs == 0) { 12518 - jsval_t code_str = js_mkstr(js, "(){}", 4); 12519 - if (is_err(code_str)) return code_str; 12520 - 12521 12538 jsval_t func_obj = mkobj(js, 0); 12522 12539 if (is_err(func_obj)) return func_obj; 12523 12540 12524 - set_slot(js, func_obj, SLOT_CODE, code_str); 12541 + set_func_code_ptr(js, func_obj, "(){}", 4); 12525 12542 set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 12526 12543 12527 12544 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); ··· 12555 12572 total_len += vstrlen(js, body); 12556 12573 total_len += 1; 12557 12574 12558 - jsval_t code_str = js_mkstr(js, NULL, total_len); 12559 - if (is_err(code_str)) return code_str; 12560 - 12561 - jsoff_t code_len, code_off = vstr(js, code_str, &code_len); 12562 - char *code_ptr = (char *)&js->mem[code_off]; 12575 + char *code_buf = (char *)malloc(total_len + 1); 12576 + if (!code_buf) return js_mkerr(js, "oom"); 12563 12577 size_t pos = 0; 12564 12578 12565 - code_ptr[pos++] = '('; 12579 + code_buf[pos++] = '('; 12566 12580 12567 12581 for (int i = 0; i < nargs - 1; i++) { 12568 12582 jsoff_t param_len, param_off = vstr(js, args[i], &param_len); 12569 - memcpy(code_ptr + pos, &js->mem[param_off], param_len); 12583 + memcpy(code_buf + pos, &js->mem[param_off], param_len); 12570 12584 pos += param_len; 12571 12585 if (i < nargs - 2) { 12572 - code_ptr[pos++] = ','; 12586 + code_buf[pos++] = ','; 12573 12587 } 12574 12588 } 12575 12589 12576 - code_ptr[pos++] = ')'; 12577 - code_ptr[pos++] = '{'; 12590 + code_buf[pos++] = ')'; 12591 + code_buf[pos++] = '{'; 12578 12592 12579 12593 jsoff_t body_len, body_off = vstr(js, body, &body_len); 12580 - memcpy(code_ptr + pos, &js->mem[body_off], body_len); 12594 + memcpy(code_buf + pos, &js->mem[body_off], body_len); 12581 12595 pos += body_len; 12582 12596 12583 - code_ptr[pos++] = '}'; 12597 + code_buf[pos++] = '}'; 12598 + code_buf[pos] = '\0'; 12584 12599 12585 12600 bool is_strict_body = is_strict_function_body((const char *)&js->mem[body_off], body_len); 12586 12601 if (is_strict_body && nargs > 1) { ··· 12595 12610 param_i = (const char *)&js->mem[param_off_i]; 12596 12611 12597 12612 if (is_strict_restricted(param_i, param_len_i)) { 12613 + free(code_buf); 12598 12614 return js_mkerr_typed(js, JS_ERR_SYNTAX, "cannot use '%.*s' as parameter name in strict mode", (int)param_len_i, param_i); 12599 12615 } 12600 12616 ··· 12607 12623 const char *param_j = (const char *)&js->mem[param_off_j]; 12608 12624 12609 12625 if (param_len_i == param_len_j && memcmp(param_i, param_j, param_len_i) == 0) { 12626 + free(code_buf); 12610 12627 return js_mkerr_typed(js, JS_ERR_SYNTAX, "duplicate parameter name '%.*s' in strict mode", (int)param_len_i, param_i); 12611 12628 } 12612 12629 ··· 12617 12634 } 12618 12635 12619 12636 jsval_t func_obj = mkobj(js, 0); 12620 - if (is_err(func_obj)) return func_obj; 12637 + if (is_err(func_obj)) { free(code_buf); return func_obj; } 12621 12638 12622 - set_slot(js, func_obj, SLOT_CODE, code_str); 12639 + set_func_code(js, func_obj, code_buf, pos); 12640 + free(code_buf); 12623 12641 set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 12624 12642 12625 12643 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 12626 - 12627 12644 jsval_t proto_setup = setup_func_prototype(js, func); 12628 12645 if (is_err(proto_setup)) return proto_setup; 12629 12646 ··· 12632 12649 12633 12650 static jsval_t builtin_AsyncFunction(struct js *js, jsval_t *args, int nargs) { 12634 12651 if (nargs == 0) { 12635 - jsval_t code_str = js_mkstr(js, "(){}", 4); 12636 - if (is_err(code_str)) return code_str; 12637 - 12638 12652 jsval_t func_obj = mkobj(js, 0); 12639 12653 if (is_err(func_obj)) return func_obj; 12640 12654 12641 - set_slot(js, func_obj, SLOT_CODE, code_str); 12655 + set_func_code_ptr(js, func_obj, "(){}", 4); 12642 12656 set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 12643 12657 set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 12644 12658 ··· 12675 12689 total_len += vstrlen(js, body); 12676 12690 total_len += 1; 12677 12691 12678 - jsval_t code_str = js_mkstr(js, NULL, total_len); 12679 - if (is_err(code_str)) return code_str; 12680 - 12681 - jsoff_t code_len, code_off = vstr(js, code_str, &code_len); 12682 - char *code_ptr = (char *)&js->mem[code_off]; 12692 + char *code_buf = (char *)malloc(total_len + 1); 12693 + if (!code_buf) return js_mkerr(js, "oom"); 12683 12694 size_t pos = 0; 12684 12695 12685 - code_ptr[pos++] = '('; 12696 + code_buf[pos++] = '('; 12686 12697 12687 12698 for (int i = 0; i < nargs - 1; i++) { 12688 12699 jsoff_t param_len, param_off = vstr(js, args[i], &param_len); 12689 - memcpy(code_ptr + pos, &js->mem[param_off], param_len); 12700 + memcpy(code_buf + pos, &js->mem[param_off], param_len); 12690 12701 pos += param_len; 12691 - if (i < nargs - 2) code_ptr[pos++] = ','; 12702 + if (i < nargs - 2) code_buf[pos++] = ','; 12692 12703 } 12693 12704 12694 - code_ptr[pos++] = ')'; 12695 - code_ptr[pos++] = '{'; 12705 + code_buf[pos++] = ')'; 12706 + code_buf[pos++] = '{'; 12696 12707 12697 12708 jsoff_t body_len, body_off = vstr(js, body, &body_len); 12698 - memcpy(code_ptr + pos, &js->mem[body_off], body_len); 12709 + memcpy(code_buf + pos, &js->mem[body_off], body_len); 12699 12710 pos += body_len; 12700 - code_ptr[pos++] = '}'; 12711 + code_buf[pos++] = '}'; 12712 + code_buf[pos] = '\0'; 12701 12713 12702 12714 jsval_t func_obj = mkobj(js, 0); 12703 - if (is_err(func_obj)) return func_obj; 12715 + if (is_err(func_obj)) { free(code_buf); return func_obj; } 12704 12716 12705 - set_slot(js, func_obj, SLOT_CODE, code_str); 12717 + set_func_code(js, func_obj, code_buf, pos); 12718 + free(code_buf); 12706 12719 set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 12707 12720 set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 12708 12721 ··· 12881 12894 if (is_err(bound_func)) return bound_func; 12882 12895 12883 12896 jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 12884 - if (vtype(code_val) == T_STR) { 12897 + if (vtype(code_val) == T_STR || vtype(code_val) == T_CFUNC) { 12885 12898 set_slot(js, bound_func, SLOT_CODE, code_val); 12899 + set_slot(js, bound_func, SLOT_CODE_LEN, get_slot(js, func_obj, SLOT_CODE_LEN)); 12886 12900 } 12887 12901 12888 12902 jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); ··· 22520 22534 22521 22535 void js_gc_update_roots(GC_UPDATE_ARGS) { 22522 22536 UTARRAY_EACH(global_scope_stack, jsoff_t, off) FWD_OFF(*off); 22537 + UTARRAY_EACH(saved_scope_stack, jsval_t, val) FWD_VAL(*val); 22523 22538 22524 22539 for (int i = 0; i < global_this_stack.depth; i++) 22525 22540 FWD_VAL(global_this_stack.stack[i]); ··· 22757 22772 return res; 22758 22773 } 22759 22774 22760 - jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 22761 - if (vtype(code_val) != T_STR) return js_mkerr(js, "function has no code"); 22762 - jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 22763 - const char *fn = (const char *) (&js->mem[fnoff]); 22775 + jsoff_t fnlen; 22776 + const char *fn = get_func_code(js, func_obj, &fnlen); 22777 + if (!fn) return js_mkerr(js, "function has no code"); 22764 22778 22765 22779 jsval_t slot_bound_this = get_slot(js, func_obj, SLOT_BOUND_THIS); 22766 22780 bool has_slot_bound_this = vtype(slot_bound_this) != T_UNDEF;
+2 -1
src/modules/json.c
··· 4 4 #include <yyjson.h> 5 5 6 6 #include "runtime.h" 7 + #include "internal.h" 7 8 #include "modules/json.h" 8 9 #include "modules/symbol.h" 9 10 ··· 85 86 if (js_type(value) != JS_OBJ) return 0; 86 87 87 88 jsval_t code = js_get_slot(js, value, SLOT_CODE); 88 - return js_type(code) == JS_STR; 89 + return js_type(code) == T_CFUNC; 89 90 } 90 91 91 92 static prop_entry *collect_props(struct js *js, jsval_t val, int *out_count) {
+45 -1
src/runtime.c
··· 1 1 #include <stdio.h> 2 2 #include <stdlib.h> 3 + #include <string.h> 3 4 #include <runtime.h> 5 + #include <arena.h> 4 6 5 7 static struct ant_runtime runtime = {0}; 8 + struct ant_runtime *const rt = &runtime; 9 + 10 + static code_block_t *code_arena_head = NULL; 11 + static code_block_t *code_arena_current = NULL; 6 12 7 - struct ant_runtime *const rt = &runtime; 13 + static code_block_t *code_arena_new_block(size_t min_size) { 14 + size_t capacity = CODE_ARENA_BLOCK_SIZE; 15 + if (min_size > capacity) capacity = min_size; 16 + 17 + code_block_t *block = (code_block_t *)ANT_GC_MALLOC_ATOMIC(sizeof(code_block_t) + capacity); 18 + if (!block) return NULL; 19 + 20 + block->next = NULL; 21 + block->used = 0; 22 + block->capacity = capacity; 23 + return block; 24 + } 25 + 26 + const char *code_arena_alloc(const char *code, size_t len) { 27 + if (!code || len == 0) return NULL; 28 + size_t alloc_size = len + 1; 29 + 30 + if (!code_arena_current || code_arena_current->used + alloc_size > code_arena_current->capacity) { 31 + code_block_t *new_block = code_arena_new_block(alloc_size); 32 + if (!new_block) return NULL; 33 + 34 + if (!code_arena_head) code_arena_head = new_block; 35 + else if (code_arena_current) code_arena_current->next = new_block; 36 + 37 + code_arena_current = new_block; 38 + } 39 + 40 + char *dest = &code_arena_current->data[code_arena_current->used]; 41 + memcpy(dest, code, len); 42 + dest[len] = '\0'; 43 + code_arena_current->used += alloc_size; 44 + 45 + return dest; 46 + } 47 + 48 + void code_arena_reset(void) { 49 + code_arena_head = NULL; 50 + code_arena_current = NULL; 51 + } 8 52 9 53 struct ant_runtime *ant_runtime_init(struct js *js, int argc, char **argv, struct arg_file *ls_p) { 10 54 runtime.js = js;