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.

allow cfunc prototypes with constructed during promotion

+101 -36
+11
include/ant.h
··· 16 16 17 17 #define STR_PROTO "__proto__" 18 18 #define STR_PROTO_LEN 9 19 + #define CFUNC_HAS_PROTOTYPE 0x01u 19 20 20 21 #define ANT_ASSERT(cond, msg) ({ \ 21 22 if (!(cond)) { \ ··· 126 127 #define js_mkfun_arity(fn, arity) ({ \ 127 128 static const ant_cfunc_meta_t _ant_cfunc_meta = { (fn), NULL, (arity), 0 }; \ 128 129 js_mkfun_meta(&_ant_cfunc_meta); \ 130 + }) 131 + 132 + #define js_mkfun_flags(fn, flags) ({ \ 133 + static const ant_cfunc_meta_t _ant_cfunc_meta = { (fn), NULL, 0, (flags) }; \ 134 + js_mkfun_meta(&_ant_cfunc_meta); \ 135 + }) 136 + 137 + #define js_mkfun_arity_flags(fn, arity, flags) ({ \ 138 + static const ant_cfunc_meta_t _ant_cfunc_meta = { (fn), NULL, (arity), (flags) }; \ 139 + js_mkfun_meta(&_ant_cfunc_meta); \ 129 140 }) 130 141 131 142 void js_set(ant_t *, ant_value_t, const char *, ant_value_t);
+53 -28
src/ant.c
··· 578 578 static ant_value_t get_prototype_for_type(ant_t *js, uint8_t type); 579 579 static ant_value_t js_cfunc_name_value(ant_t *js, ant_value_t cfunc); 580 580 static ant_value_t js_cfunc_length_value(ant_value_t cfunc); 581 + static bool js_cfunc_has_prototype(ant_value_t cfunc); 582 + static ant_value_t setup_func_prototype_property(ant_t *js, ant_value_t func, bool mark_constructor); 581 583 static ant_value_t js_expose_cfunc_for_key(ant_t *js, ant_value_t value, const char *key, size_t key_len); 582 584 583 585 static inline ant_value_t lkp_val(ant_t *js, ant_value_t obj, const char *buf, size_t len); ··· 974 976 975 977 if (key_len == 6 && memcmp(key, "length", 6) == 0) { 976 978 *out = js_cfunc_length_value(cfunc); 979 + return true; 980 + } 981 + 982 + if (key_len == 9 && memcmp(key, "prototype", 9) == 0 && js_cfunc_has_prototype(cfunc)) { 983 + ant_value_t promoted = js_cfunc_promote(js, cfunc); 984 + if (is_err(promoted)) { 985 + *out = promoted; 986 + return true; 987 + } 988 + *out = js_get(js, promoted, "prototype"); 977 989 return true; 978 990 } 979 991 ··· 3326 3338 } 3327 3339 3328 3340 static ant_value_t setup_func_prototype(ant_t *js, ant_value_t func) { 3329 - ant_value_t proto_obj = mkobj(js, 0); 3330 - if (is_err(proto_obj)) return proto_obj; 3331 - 3332 - ant_value_t object_proto = js->sym.object_proto; 3333 - if (vtype(object_proto) == T_OBJ) { 3334 - js_set_proto_init(proto_obj, object_proto); 3335 - } 3336 - 3337 - ant_value_t constructor_key = js_mkstr(js, "constructor", 11); 3338 - if (is_err(constructor_key)) return constructor_key; 3339 - 3340 - ant_value_t res = mkprop(js, proto_obj, constructor_key, func, 0); 3341 - if (is_err(res)) return res; 3342 - js_set_descriptor(js, proto_obj, "constructor", 11, JS_DESC_W | JS_DESC_C); 3343 - 3344 - ant_value_t prototype_key = js_mkstr(js, "prototype", 9); 3345 - if (is_err(prototype_key)) return prototype_key; 3346 - 3347 - res = js_setprop(js, func, prototype_key, proto_obj); 3348 - if (is_err(res)) return res; 3349 - js_set_descriptor(js, js_as_obj(func), "prototype", 9, JS_DESC_W); 3350 - 3351 - js_mark_constructor(func, true); 3352 - 3353 - return js_mkundef(); 3341 + return setup_func_prototype_property(js, func, true); 3354 3342 } 3355 3343 3356 3344 static inline bool same_object_identity(ant_value_t a, ant_value_t b) { ··· 7633 7621 ant_value_t arr = mkarr(js); 7634 7622 ant_offset_t idx = 0; 7635 7623 arr_set(js, arr, idx++, js->length_str); 7636 - if (vtype(js_cfunc_name_value(js, obj)) == T_STR) { 7637 - arr_set(js, arr, idx++, ANT_STRING("name")); 7638 - } 7624 + 7625 + if (vtype(js_cfunc_name_value(js, obj)) == T_STR) arr_set(js, arr, idx++, ANT_STRING("name")); 7626 + if (js_cfunc_has_prototype(obj)) arr_set(js, arr, idx++, ANT_STRING("prototype")); 7627 + 7639 7628 return mkval(T_ARR, vdata(arr)); 7640 7629 } 7641 7630 ··· 14518 14507 return tov((double)js_cfunc_length(cfunc)); 14519 14508 } 14520 14509 14510 + static bool js_cfunc_has_prototype(ant_value_t cfunc) { 14511 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(cfunc); 14512 + return meta && (meta->flags & CFUNC_HAS_PROTOTYPE) != 0; 14513 + } 14514 + 14515 + static ant_value_t setup_func_prototype_property(ant_t *js, ant_value_t func, bool mark_constructor) { 14516 + ant_value_t proto_obj = mkobj(js, 0); 14517 + if (is_err(proto_obj)) return proto_obj; 14518 + 14519 + ant_value_t object_proto = js->sym.object_proto; 14520 + if (vtype(object_proto) == T_OBJ) js_set_proto_init(proto_obj, object_proto); 14521 + 14522 + ant_value_t constructor_key = js_mkstr(js, "constructor", 11); 14523 + if (is_err(constructor_key)) return constructor_key; 14524 + 14525 + ant_value_t res = mkprop(js, proto_obj, constructor_key, func, 0); 14526 + if (is_err(res)) return res; 14527 + js_set_descriptor(js, proto_obj, "constructor", 11, JS_DESC_W | JS_DESC_C); 14528 + 14529 + ant_value_t prototype_key = js_mkstr(js, "prototype", 9); 14530 + if (is_err(prototype_key)) return prototype_key; 14531 + 14532 + res = js_setprop(js, func, prototype_key, proto_obj); 14533 + if (is_err(res)) return res; 14534 + js_set_descriptor(js, js_as_obj(func), "prototype", 9, JS_DESC_W); 14535 + 14536 + if (mark_constructor) js_mark_constructor(func, true); 14537 + 14538 + return js_mkundef(); 14539 + } 14540 + 14521 14541 ant_value_t js_cfunc_expose_named(ant_t *js, ant_value_t cfunc, const char *name, size_t name_len) { 14522 14542 if (vtype(cfunc) != T_CFUNC || !name || is_internal_prop(name, (ant_offset_t)name_len)) return cfunc; 14523 14543 ··· 14611 14631 } 14612 14632 14613 14633 ant_value_t promoted = js_obj_to_func(fn_obj); 14634 + 14635 + if (js_cfunc_has_prototype(cfunc)) { 14636 + ant_value_t proto_result = setup_func_prototype_property(js, promoted, false); 14637 + if (is_err(proto_result)) return proto_result; 14638 + } 14614 14639 14615 14640 if (js->cfunc_promote_cache.len >= js->cfunc_promote_cache.cap) { 14616 14641 uint8_t new_cap = js->cfunc_promote_cache.cap ? js->cfunc_promote_cache.cap * 2 : 4;
+1 -1
src/modules/fetch.c
··· 903 903 904 904 void init_fetch_module() { 905 905 utarray_new(pending_requests, &ut_ptr_icd); 906 - js_set(rt->js, rt->js->global, "fetch", js_mkfun(js_fetch)); 906 + js_set(rt->js, rt->js->global, "fetch", js_mkfun_flags(js_fetch, CFUNC_HAS_PROTOTYPE)); 907 907 } 908 908 909 909 int has_pending_fetches(void) {
+19 -1
src/modules/io.c
··· 849 849 } 850 850 851 851 if (t == T_CFUNC) { 852 - fprintf(stream, "<native function 0x%" PRIx64 ">", (uint64_t)vdata(val)); 852 + ant_value_t promoted = js_cfunc_lookup_promoted(js, val); 853 + if (vtype(promoted) == T_FUNC) { 854 + if (depth > 10) fprintf(stream, "<Function @%" PRIu64 " ...>", (uint64_t)vdata(js_as_obj(promoted))); 855 + else inspect_object(js, promoted, stream, depth, visited); 856 + return; 857 + } 858 + 859 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(val); 860 + const char *name = (meta && meta->name) ? meta->name : NULL; 861 + uint32_t length = js_cfunc_length(val); 862 + bool has_prototype = meta && (meta->flags & CFUNC_HAS_PROTOTYPE) != 0; 863 + 864 + if (name) fprintf(stream, "[Function: %s]", name); 865 + else fprintf(stream, "[Function]"); 866 + 867 + fprintf(stream, " <native ptr 0x%" PRIx64 ", length=%u", (uint64_t)vdata(val), length); 868 + if (has_prototype) fprintf(stream, ", prototype"); 869 + fprintf(stream, ">"); 870 + 853 871 return; 854 872 } 855 873
+6 -6
src/modules/timer.c
··· 779 779 } 780 780 781 781 static void timers_define_common(ant_t *js, ant_value_t obj) { 782 - js_set(js, obj, "setTimeout", js_mkfun(js_set_timeout)); 783 - js_set(js, obj, "clearTimeout", js_mkfun(js_clear_timeout)); 784 - js_set(js, obj, "setInterval", js_mkfun(js_set_interval)); 785 - js_set(js, obj, "clearInterval", js_mkfun(js_clear_timeout)); 786 - js_set(js, obj, "setImmediate", js_mkfun(js_set_immediate)); 787 - js_set(js, obj, "clearImmediate", js_mkfun(js_clear_immediate)); 782 + js_set(js, obj, "setTimeout", js_mkfun_flags(js_set_timeout, CFUNC_HAS_PROTOTYPE)); 783 + js_set(js, obj, "clearTimeout", js_mkfun_flags(js_clear_timeout, CFUNC_HAS_PROTOTYPE)); 784 + js_set(js, obj, "setInterval", js_mkfun_flags(js_set_interval, CFUNC_HAS_PROTOTYPE)); 785 + js_set(js, obj, "clearInterval", js_mkfun_flags(js_clear_timeout, CFUNC_HAS_PROTOTYPE)); 786 + js_set(js, obj, "setImmediate", js_mkfun_flags(js_set_immediate, CFUNC_HAS_PROTOTYPE)); 787 + js_set(js, obj, "clearImmediate", js_mkfun_flags(js_clear_immediate, CFUNC_HAS_PROTOTYPE)); 788 788 js_set(js, obj, "queueMicrotask", js_mkfun(js_queue_microtask)); 789 789 } 790 790
+11
tests/test_native_method_descriptors.cjs
··· 202 202 const fetchOwnNames = Object.getOwnPropertyNames(fetch); 203 203 const fetchOwnSymbols = Object.getOwnPropertySymbols(fetch); 204 204 205 + if (!fetchOwnNames.includes('prototype')) { 206 + console.log('FAIL: native functions with prototype metadata should expose prototype in own property names'); 207 + pass = false; 208 + } 209 + 205 210 if (!fetchOwnNames.includes('extra') || !fetchOwnNames.includes('defined')) { 206 211 console.log('FAIL: native function own property names should include promoted writes'); 207 212 pass = false; ··· 215 220 const extraDesc = Object.getOwnPropertyDescriptor(fetch, 'extra'); 216 221 const definedDesc = Object.getOwnPropertyDescriptor(fetch, 'defined'); 217 222 const symDesc = Object.getOwnPropertyDescriptor(fetch, nativeReproSym); 223 + const prototypeDesc = Object.getOwnPropertyDescriptor(fetch, 'prototype'); 218 224 219 225 if (!extraDesc || extraDesc.value !== 'value-from-set' || !extraDesc.enumerable || !extraDesc.configurable || !extraDesc.writable) { 220 226 console.log('FAIL: promoted native string properties should keep their descriptors'); ··· 228 234 229 235 if (!symDesc || symDesc.value !== 'symbol-value' || !symDesc.enumerable || !symDesc.configurable || !symDesc.writable) { 230 236 console.log('FAIL: promoted native symbol properties should keep their descriptors'); 237 + pass = false; 238 + } 239 + 240 + if (!prototypeDesc || prototypeDesc.enumerable || prototypeDesc.configurable || !prototypeDesc.writable) { 241 + console.log('FAIL: native function prototype descriptors should match built-in function defaults'); 231 242 pass = false; 232 243 } 233 244