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.

[big] allow promotion from T_CFUNC to metadata backed object

+626 -167
+1 -1
examples/results.txt
··· 1307 1307 compat-table/es2019/misc.Function-toString.class-explicit-constructor.js: failed 1308 1308 compat-table/es2019/misc.Function-toString.class-implicit-constructor.js: failed 1309 1309 compat-table/es2019/misc.Function-toString.computed-names.js: failed 1310 - compat-table/es2019/misc.Function-toString.native-code.js: failed 1310 + compat-table/es2019/misc.Function-toString.native-code.js: OK 1311 1311 compat-table/es2019/misc.Function-toString.unicode-escapes.js: failed 1312 1312 compat-table/es2019/misc.JSON-stringify-well-formed.js: OK 1313 1313 compat-table/es2019/misc.JSON-superset.line-separator.js: OK
+16 -2
include/ant.h
··· 102 102 103 103 ant_value_t js_mkobj(ant_t *); 104 104 ant_value_t js_mkobj_with_inobj_limit(ant_t *, uint8_t inobj_limit); 105 + 105 106 ant_value_t js_newobj(ant_t *); 106 107 ant_value_t js_mkarr(ant_t *); 107 108 ant_value_t js_mkstr(ant_t *, const void *, size_t); 108 109 ant_value_t js_mkstr_permanent(ant_t *, const void *, size_t); 109 110 ant_value_t js_mkbigint(ant_t *, const char *digits, size_t len, bool negative); 111 + 110 112 ant_value_t js_mksym(ant_t *, const char *desc); 111 113 ant_value_t js_mksym_well_known(ant_t *, const char *desc); 112 - ant_value_t js_mkfun(ant_value_t (*fn)(ant_t *, ant_value_t *, int)); 114 + ant_value_t js_mkfun_meta(const ant_cfunc_meta_t *meta); 115 + ant_value_t js_mkfun_dyn(ant_cfunc_t fn); 116 + 113 117 ant_value_t js_heavy_mkfun(ant_t *js, ant_value_t (*fn)(ant_t *, ant_value_t *, int), ant_value_t data); 114 - 115 118 ant_value_t js_mkprop_fast(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v); 116 119 ant_offset_t js_mkprop_fast_off(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v); 117 120 121 + #define js_mkfun(fn) ({ \ 122 + static const ant_cfunc_meta_t _ant_cfunc_meta = { (fn), NULL, 0, 0 }; \ 123 + js_mkfun_meta(&_ant_cfunc_meta); \ 124 + }) 125 + 126 + #define js_mkfun_arity(fn, arity) ({ \ 127 + static const ant_cfunc_meta_t _ant_cfunc_meta = { (fn), NULL, (arity), 0 }; \ 128 + js_mkfun_meta(&_ant_cfunc_meta); \ 129 + }) 130 + 118 131 void js_set(ant_t *, ant_value_t, const char *, ant_value_t); 132 + void js_set_exact(ant_t *, ant_value_t, const char *, ant_value_t); 119 133 void js_set_sym(ant_t *, ant_value_t obj, ant_value_t sym, ant_value_t val); 120 134 void js_set_symbol(ant_t *, ant_value_t obj, const char *key, ant_value_t val); 121 135 void js_saveval(ant_t *js, ant_offset_t off, ant_value_t v);
+43 -12
include/internal.h
··· 253 253 uint8_t cap; 254 254 } cfunc_promote_cache; 255 255 256 + struct { 257 + const ant_cfunc_meta_t **base_meta; 258 + const char **name_ptr; 259 + ant_value_t *named; 260 + uint16_t len; 261 + uint16_t cap; 262 + } cfunc_name_cache; 263 + 256 264 bool owns_mem; 257 265 bool fatal_error; 258 266 bool thrown_exists; ··· 311 319 PROP_META_SYMBOL = 1, 312 320 } prop_meta_key_t; 313 321 314 - typedef ant_value_t 315 - (*js_cfunc_fn_t)(ant_t *, ant_value_t *, int); 316 - 317 - static inline js_cfunc_fn_t js_as_cfunc(ant_value_t fn_val) { 318 - return (js_cfunc_fn_t)(uintptr_t)vdata(fn_val); 319 - } 320 - 321 322 static inline bool is_err(ant_value_t v) { 322 323 return vtype(v) == T_ERR; 323 324 } ··· 339 340 return t == T_FUNC || t == T_CFUNC; 340 341 } 341 342 343 + static inline const ant_cfunc_meta_t *js_as_cfunc_meta(ant_value_t fn_val) { 344 + return (const ant_cfunc_meta_t *)(uintptr_t)vdata(fn_val); 345 + } 346 + 347 + static inline ant_cfunc_t js_as_cfunc(ant_value_t fn_val) { 348 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); 349 + return meta ? meta->fn : NULL; 350 + } 351 + 352 + static inline uint32_t js_cfunc_length(ant_value_t fn_val) { 353 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); 354 + return meta ? meta->length : 0; 355 + } 356 + 357 + static inline bool js_cfunc_same_entrypoint(ant_value_t fn_val, ant_cfunc_t fn) { 358 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(fn_val); 359 + return meta && meta->fn == fn; 360 + } 361 + 342 362 bool is_internal_prop(const char *key, ant_offset_t klen); 343 363 size_t uint_to_str(char *buf, size_t bufsize, uint64_t val); 344 364 int extract_array_args(ant_t *js, ant_value_t arr, ant_value_t **out_args); ··· 353 373 ant_value_t js_propref_load(ant_t *js, ant_offset_t handle); 354 374 ant_value_t mkprop(ant_t *js, ant_value_t obj, ant_value_t k, ant_value_t v, uint8_t attrs); 355 375 ant_value_t mkprop_interned(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs); 376 + ant_value_t mkprop_interned_exact(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs); 356 377 ant_value_t setprop_cstr(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v); 357 378 ant_value_t setprop_interned(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v); 358 379 ant_value_t js_define_property(ant_t *js, ant_value_t obj, ant_value_t prop, ant_value_t descriptor, bool reflect_mode); ··· 546 567 ); 547 568 } 548 569 570 + static inline ant_value_t defalias(ant_t *js, ant_value_t obj, const char *name, size_t len, ant_value_t fn) { 571 + const char *interned = intern_string(name, len); 572 + if (!interned) return js_mkerr(js, "oom"); 573 + 574 + return mkprop_interned_exact( 575 + js, obj, interned, fn, 576 + ANT_PROP_ATTR_WRITABLE | ANT_PROP_ATTR_CONFIGURABLE 577 + ); 578 + } 579 + 549 580 static inline ant_flat_string_t *str_flat_from_bytes(const char *str) { 550 581 return (ant_flat_string_t *)((char *)str - offsetof(ant_flat_string_t, bytes)); 551 582 } ··· 594 625 } 595 626 596 627 ant_value_t js_cfunc_promote(ant_t *js, ant_value_t cfunc); 628 + ant_value_t js_cfunc_expose_named(ant_t *js, ant_value_t cfunc, const char *name, size_t name_len); 597 629 598 630 static inline ant_value_t js_cfunc_lookup_promoted(ant_t *js, ant_value_t cfunc) { 599 631 uintptr_t ptr = vdata(cfunc); 600 - for (uint8_t i = 0; i < js->cfunc_promote_cache.len; i++) { 601 - if (js->cfunc_promote_cache.cfunc_ptr[i] == ptr) 602 - return js->cfunc_promote_cache.promoted[i]; 603 - } 632 + for (uint8_t i = 0; i < js->cfunc_promote_cache.len; i++) if ( 633 + js->cfunc_promote_cache.cfunc_ptr[i] == ptr 634 + ) return js->cfunc_promote_cache.promoted[i]; 604 635 return cfunc; 605 636 } 606 637 607 638 static inline ant_value_t js_make_ctor(ant_t *js, ant_cfunc_t fn, ant_value_t proto, const char *name, size_t nlen) { 608 639 ant_value_t obj = js_mkobj(js); 609 - js_set_slot(obj, SLOT_CFUNC, js_mkfun(fn)); 640 + js_set_slot(obj, SLOT_CFUNC, js_mkfun_dyn(fn)); 610 641 js_mkprop_fast(js, obj, "prototype", 9, proto); 611 642 js_mkprop_fast(js, obj, "name", 4, js_mkstr(js, name, nlen)); 612 643 js_set_descriptor(js, obj, "name", 4, 0);
+10 -1
include/types.h
··· 26 26 typedef uint64_t ant_offset_t; 27 27 typedef uint64_t ant_value_t; 28 28 29 - typedef ant_value_t (*ant_cfunc_t) (ant_t *, ant_value_t *, int); 29 + typedef ant_value_t 30 + (*ant_cfunc_t) 31 + (ant_t *, ant_value_t *, int); 32 + 33 + typedef struct ant_cfunc_meta { 34 + ant_cfunc_t fn; 35 + const char *name; 36 + uint32_t length; 37 + uint8_t flags; 38 + } ant_cfunc_meta_t; 30 39 31 40 #define ant_bind_t ant_value_t func, ant_value_t this_val 32 41 #define ant_params_t ant_t *js, ant_value_t *args, int nargs
+367 -77
src/ant.c
··· 574 574 static bool parse_func_params(ant_t *js, uint8_t *flags, int *out_count); 575 575 static bool try_dynamic_setter(ant_t *js, ant_value_t obj, const char *key, size_t key_len, ant_value_t value); 576 576 static uintptr_t lkp_with_setter(ant_t *js, ant_value_t obj, const char *buf, size_t len, ant_value_t *setter_out, bool *has_setter_out); 577 - static ant_value_t call_proto_accessor(ant_t *js, ant_value_t prim, ant_value_t accessor, bool has_accessor, ant_value_t *arg, int arg_count, bool is_setter); 577 + 578 578 static ant_value_t get_prototype_for_type(ant_t *js, uint8_t type); 579 + static ant_value_t js_cfunc_name_value(ant_t *js, ant_value_t cfunc); 580 + static ant_value_t js_cfunc_length_value(ant_value_t cfunc); 581 + static ant_value_t js_expose_cfunc_for_key(ant_t *js, ant_value_t value, const char *key, size_t key_len); 579 582 580 583 static inline ant_value_t lkp_val(ant_t *js, ant_value_t obj, const char *buf, size_t len); 581 584 static inline ant_value_t lkp_sym_proto_val(ant_t *js, ant_value_t obj, ant_offset_t sym_off); ··· 937 940 } 938 941 939 942 static const char *get_func_name(ant_t *js, ant_value_t func, ant_offset_t *out_len) { 943 + if (vtype(func) == T_CFUNC) { 944 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(func); 945 + if (!meta || !meta->name) return NULL; 946 + if (out_len) *out_len = (ant_offset_t)strlen(meta->name); 947 + return meta->name; 948 + } 949 + 940 950 if (vtype(func) != T_FUNC) return NULL; 941 - ant_value_t name = lkp_val(js, js_func_obj(func), "name", 4); 942 - if (vtype(name) != T_STR) return NULL; 943 - ant_offset_t str_off = vstr(js, name, out_len); 944 - return (const char *)(uintptr_t)(str_off); 951 + ant_value_t func_obj = js_func_obj(func); 952 + ant_value_t name = lkp_val(js, func_obj, "name", 4); 953 + 954 + if (vtype(name) == T_STR) { 955 + ant_offset_t str_off = vstr(js, name, out_len); 956 + return (const char *)(uintptr_t)(str_off); 957 + } 958 + 959 + ant_value_t cfunc_slot = get_slot(func_obj, SLOT_CFUNC); 960 + if (vtype(cfunc_slot) == T_CFUNC) return get_func_name(js, cfunc_slot, out_len); 961 + 962 + return NULL; 963 + } 964 + 965 + static bool js_cfunc_try_get_own(ant_t *js, ant_value_t cfunc, const char *key, size_t key_len, ant_value_t *out) { 966 + if (key_len == 4 && memcmp(key, "name", 4) == 0) { 967 + ant_value_t name = js_cfunc_name_value(js, cfunc); 968 + if (vtype(name) != T_UNDEF) { 969 + *out = name; 970 + return true; 971 + } 972 + return false; 973 + } 974 + 975 + if (key_len == 6 && memcmp(key, "length", 6) == 0) { 976 + *out = js_cfunc_length_value(cfunc); 977 + return true; 978 + } 979 + 980 + return false; 945 981 } 946 982 947 983 static const char *get_class_name(ant_t *js, ant_value_t obj, ant_offset_t *out_len, const char *skip) { ··· 2227 2263 ant_value_t async_slot = get_slot(func_obj, SLOT_ASYNC); 2228 2264 2229 2265 bool is_async = (async_slot == js_true); 2230 - bool has_code = (vtype(code_slot) == T_CFUNC); 2266 + bool has_code = (vtype(code_slot) == T_NTARG); 2231 2267 2232 2268 const struct func_format *fmt = &formats[is_async]; 2233 2269 ··· 2283 2319 return cpy(buf, len, fmt->anon, fmt->anon_len); 2284 2320 } 2285 2321 2322 + static size_t strcfunc(ant_t *js, ant_value_t value, char *buf, size_t len) { 2323 + ant_offset_t name_len = 0; 2324 + const char *name = get_func_name(js, value, &name_len); 2325 + const struct func_format *fmt = &formats[0]; 2326 + 2327 + if (name && name_len > 0) { 2328 + size_t n = cpy(buf, len, fmt->prefix, fmt->prefix_len); 2329 + n += cpy(buf + n, REMAIN(n, len), name, name_len); 2330 + n += cpy(buf + n, REMAIN(n, len), "]", 1); 2331 + return n; 2332 + } 2333 + 2334 + return cpy(buf, len, fmt->anon, fmt->anon_len); 2335 + } 2336 + 2286 2337 static size_t tostr(ant_t *js, ant_value_t value, char *buf, size_t len) { 2287 2338 switch (vtype(value)) { 2288 2339 case T_UNDEF: return ANT_COPY(buf, len, "undefined"); ··· 2300 2351 case T_BIGINT: return strbigint(js, value, buf, len); 2301 2352 case T_PROMISE: return strpromise(js, value, buf, len); 2302 2353 case T_FUNC: return strfunc(js, value, buf, len); 2303 - 2304 - case T_CFUNC: return ANT_COPY(buf, len, "[native code]"); 2354 + case T_CFUNC: return strcfunc(js, value, buf, len); 2305 2355 case T_FFI: return ANT_COPY(buf, len, "[native code (ffi)]"); 2306 2356 2307 2357 case T_ERR: { ··· 2424 2474 static const void *jump_table[] = { 2425 2475 [T_OBJ] = &&L_OBJ, [T_STR] = &&L_STR, 2426 2476 [T_UNDEF] = &&L_UNDEF, [T_NULL] = &&L_NULL, [T_NUM] = &&L_NUM, 2427 - [T_BOOL] = &&L_BOOL, [T_FUNC] = &&L_OBJ, [T_CFUNC] = &&L_DEFAULT, 2477 + [T_BOOL] = &&L_BOOL, [T_FUNC] = &&L_OBJ, [T_CFUNC] = &&L_OBJ, 2428 2478 [T_ERR] = &&L_DEFAULT, [T_ARR] = &&L_OBJ, 2429 2479 [T_PROMISE] = &&L_DEFAULT, [T_TYPEDARRAY] = &&L_DEFAULT, 2430 2480 [T_BIGINT] = &&L_BIGINT, [T_SYMBOL] = &&L_DEFAULT, ··· 3006 3056 const char *p = (const char *)(uintptr_t)(koff); 3007 3057 const char *interned = intern_string(p, klen); 3008 3058 if (!interned) return js_mkerr(js, "oom"); 3059 + v = js_expose_cfunc_for_key(js, v, interned, (size_t)klen); 3060 + if (is_err(v)) return v; 3009 3061 3010 3062 int32_t found = ant_shape_lookup_interned(ptr->shape, interned); 3011 3063 if (found >= 0) { ··· 3013 3065 if (!js_obj_ensure_unique_shape(ptr)) return js_mkerr(js, "oom"); 3014 3066 ant_shape_set_attrs_interned(ptr->shape, interned, attrs); 3015 3067 } else { 3016 - if (!ant_shape_add_interned_tr(&ptr->shape, interned, attrs, &slot)) { 3017 - return js_mkerr(js, "oom"); 3018 - } 3068 + if (!ant_shape_add_interned_tr(&ptr->shape, interned, attrs, &slot)) return js_mkerr(js, "oom"); 3019 3069 added = true; 3020 3070 } 3021 3071 } ··· 3027 3077 if (slot >= ptr->prop_count && !js_obj_ensure_prop_capacity(ptr, slot + 1)) { 3028 3078 return js_mkerr(js, "oom"); 3029 3079 } 3080 + 3030 3081 ant_object_prop_set_unchecked(ptr, slot, v); 3031 3082 gc_write_barrier(js, ptr, v); 3032 3083 3033 3084 return v; 3034 3085 } 3035 3086 3036 - ant_value_t mkprop_interned(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs) { 3087 + static ant_value_t mkprop_interned_impl( 3088 + ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs, bool expose_cfunc 3089 + ) { 3037 3090 obj = js_as_obj(obj); 3038 3091 ant_object_t *ptr = js_obj_ptr(obj); 3092 + 3039 3093 if (!ptr || !ptr->shape || !interned_key) return js_mkerr(js, "invalid object"); 3094 + if (expose_cfunc) { 3095 + v = js_expose_cfunc_for_key(js, v, interned_key, strlen(interned_key)); 3096 + if (is_err(v)) return v; 3097 + } 3040 3098 3041 3099 if (!attrs) attrs = ANT_PROP_ATTR_DEFAULT; 3042 3100 3043 3101 uint32_t slot = 0; 3044 3102 bool added = false; 3045 3103 int32_t found = ant_shape_lookup_interned(ptr->shape, interned_key); 3104 + 3046 3105 if (found >= 0) { 3047 3106 slot = (uint32_t)found; 3048 3107 if (!js_obj_ensure_unique_shape(ptr)) return js_mkerr(js, "oom"); 3049 3108 ant_shape_set_attrs_interned(ptr->shape, interned_key, attrs); 3050 3109 } else { 3051 - if (!ant_shape_add_interned_tr(&ptr->shape, interned_key, attrs, &slot)) { 3052 - return js_mkerr(js, "oom"); 3053 - } 3110 + if (!ant_shape_add_interned_tr(&ptr->shape, interned_key, attrs, &slot)) return js_mkerr(js, "oom"); 3054 3111 added = true; 3055 3112 } 3056 3113 ··· 3060 3117 if (slot >= ptr->prop_count && !js_obj_ensure_prop_capacity(ptr, slot + 1)) { 3061 3118 return js_mkerr(js, "oom"); 3062 3119 } 3120 + 3063 3121 ant_object_prop_set_unchecked(ptr, slot, v); 3064 3122 gc_write_barrier(js, ptr, v); 3123 + 3065 3124 return v; 3066 3125 } 3067 3126 3127 + ant_value_t mkprop_interned(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs) { 3128 + return mkprop_interned_impl(js, obj, interned_key, v, attrs, true); 3129 + } 3130 + 3131 + ant_value_t mkprop_interned_exact(ant_t *js, ant_value_t obj, const char *interned_key, ant_value_t v, uint8_t attrs) { 3132 + return mkprop_interned_impl(js, obj, interned_key, v, attrs, false); 3133 + } 3134 + 3068 3135 ant_value_t js_mkprop_fast(ant_t *js, ant_value_t obj, const char *key, size_t len, ant_value_t v) { 3069 3136 const char *interned = intern_string(key, len); 3070 3137 if (!interned) return js_mkerr(js, "oom"); ··· 3082 3149 void js_saveval(ant_t *js, ant_offset_t off, ant_value_t v) { 3083 3150 bool ok = propref_store(js, off, v); 3084 3151 assert(ok && "js_saveval expects a valid property handle"); 3085 - (void)ok; 3086 3152 } 3087 3153 3088 3154 static void set_slot(ant_value_t obj, internal_slot_t slot, ant_value_t val) { ··· 3137 3203 } 3138 3204 3139 3205 static void set_func_code_ptr(ant_t *js, ant_value_t func_obj, const char *code, size_t len) { 3140 - set_slot(func_obj, SLOT_CODE, mkval(T_CFUNC, (size_t)code)); 3206 + set_slot(func_obj, SLOT_CODE, mkval(T_NTARG, (size_t)code)); 3141 3207 set_slot(func_obj, SLOT_CODE_LEN, tov((double)len)); 3142 3208 } 3143 3209 ··· 3151 3217 ant_value_t code_val = get_slot(func_obj, SLOT_CODE); 3152 3218 ant_value_t len_val = get_slot(func_obj, SLOT_CODE_LEN); 3153 3219 3154 - if (vtype(code_val) != T_CFUNC) { 3220 + if (vtype(code_val) != T_NTARG) { 3155 3221 if (len) *len = 0; 3156 3222 return NULL; 3157 3223 } 3158 3224 3159 3225 if (len) *len = (ant_offset_t)tod(len_val); 3160 - return (const char *)vdata(code_val); 3226 + return (const char *)(uintptr_t)vdata(code_val); 3161 3227 } 3162 3228 3163 3229 static inline bool js_is_trim_space(char ch) { ··· 3742 3808 return false; 3743 3809 } 3744 3810 3811 + static ant_value_t call_proto_accessor( 3812 + ant_t *js, ant_value_t prim, ant_value_t accessor, bool has_accessor, 3813 + ant_value_t *arg, int arg_count, bool is_setter 3814 + ) { 3815 + if (!has_accessor || (vtype(accessor) != T_FUNC && vtype(accessor) != T_CFUNC)) 3816 + return js_mkundef(); 3817 + 3818 + js_error_site_t saved_errsite = js->errsite; 3819 + ant_value_t result = sv_vm_call(sv_vm_get_active(js), js, accessor, prim, arg, arg_count, NULL, false); 3820 + 3821 + bool had_throw = js->thrown_exists; 3822 + ant_value_t thrown = js->thrown_value; 3823 + js->errsite = saved_errsite; 3824 + 3825 + if (had_throw) { 3826 + js->thrown_exists = true; 3827 + js->thrown_value = thrown; 3828 + } 3829 + 3830 + if (is_setter) return is_err(result) ? result : (arg ? *arg : js_mkundef()); 3831 + return result; 3832 + } 3833 + 3745 3834 // TODO: decompose into smaller helpers 3746 3835 ant_value_t js_setprop(ant_t *js, ant_value_t obj, ant_value_t k, ant_value_t v) { 3747 3836 uint8_t ot = vtype(obj); ··· 3829 3918 3830 3919 ant_offset_t klen; ant_offset_t koff = vstr(js, k, &klen); 3831 3920 const char *key = (char *)(uintptr_t)(koff); 3921 + 3922 + v = js_expose_cfunc_for_key(js, v, key, (size_t)klen); 3923 + if (is_err(v)) return v; 3832 3924 3833 3925 if (array_obj_ptr(obj) && klen > 0 && key[0] >= '0' && key[0] <= '9') { 3834 3926 ant_arguments_state_t *args_state = js_arguments_state(obj); ··· 3983 4075 3984 4076 ant_value_t js_define_own_prop(ant_t *js, ant_value_t obj, const char *key, size_t klen, ant_value_t v) { 3985 4077 obj = js_as_obj(obj); 4078 + v = js_expose_cfunc_for_key(js, v, key, klen); 4079 + if (is_err(v)) return v; 3986 4080 if (is_proxy(obj)) { 3987 4081 ant_value_t result = proxy_set(js, obj, key, klen, v); 3988 4082 if (is_err(result)) return result; ··· 4367 4461 return 0; 4368 4462 } 4369 4463 4370 - static ant_value_t call_proto_accessor( 4371 - ant_t *js, ant_value_t prim, ant_value_t accessor, bool has_accessor, 4372 - ant_value_t *arg, int arg_count, bool is_setter 4373 - ) { 4374 - if (!has_accessor || (vtype(accessor) != T_FUNC && vtype(accessor) != T_CFUNC)) 4375 - return js_mkundef(); 4376 - 4377 - js_error_site_t saved_errsite = js->errsite; 4378 - ant_value_t result = sv_vm_call(sv_vm_get_active(js), js, accessor, prim, arg, arg_count, NULL, false); 4379 - 4380 - bool had_throw = js->thrown_exists; 4381 - ant_value_t thrown = js->thrown_value; 4382 - js->errsite = saved_errsite; 4383 - 4384 - if (had_throw) { 4385 - js->thrown_exists = true; 4386 - js->thrown_value = thrown; 4387 - } 4388 - 4389 - if (is_setter) return is_err(result) ? result : (arg ? *arg : js_mkundef()); 4390 - return result; 4391 - } 4392 - 4393 4464 ant_value_t js_get_proto(ant_t *js, ant_value_t obj) { 4394 4465 uint8_t t = vtype(obj); 4395 4466 ··· 4451 4522 4452 4523 static ant_value_t get_prototype_for_type(ant_t *js, uint8_t type) { 4453 4524 switch (type) { 4454 - case T_OBJ: return js->sym.object_proto; 4455 - case T_ARR: return js->sym.array_proto; 4456 - case T_STR: return get_ctor_proto(js, "String", 6); 4457 - case T_NUM: return get_ctor_proto(js, "Number", 6); 4458 - case T_BOOL: return get_ctor_proto(js, "Boolean", 7); 4459 - case T_FUNC: return get_ctor_proto(js, "Function", 8); 4460 - case T_PROMISE: return get_ctor_proto(js, "Promise", 7); 4525 + case T_OBJ: return js->sym.object_proto; 4526 + case T_ARR: return js->sym.array_proto; 4527 + case T_STR: return get_ctor_proto(js, "String", 6); 4528 + case T_NUM: return get_ctor_proto(js, "Number", 6); 4529 + case T_BOOL: return get_ctor_proto(js, "Boolean", 7); 4530 + case T_FUNC: return get_ctor_proto(js, "Function", 8); 4531 + case T_PROMISE: return get_ctor_proto(js, "Promise", 7); 4461 4532 case T_GENERATOR: return js->sym.generator_proto; 4462 - case T_BIGINT: return get_ctor_proto(js, "BigInt", 6); 4463 - case T_SYMBOL: return get_ctor_proto(js, "Symbol", 6); 4464 - default: return js_mknull(); 4533 + case T_BIGINT: return get_ctor_proto(js, "BigInt", 6); 4534 + case T_SYMBOL: return get_ctor_proto(js, "Symbol", 6); 4535 + default: return js_mknull(); 4465 4536 }} 4466 4537 4467 4538 ant_offset_t lkp_proto(ant_t *js, ant_value_t obj, const char *key, size_t len) { ··· 4764 4835 js->this_val = obj; 4765 4836 4766 4837 ant_value_t result; 4767 - if (ft == T_CFUNC) result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(fn))(js, args, nargs); 4838 + if (ft == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs); 4768 4839 else result = sv_vm_call(js->vm, js, fn, obj, args, nargs, NULL, false); 4769 4840 4770 4841 bool had_throw = js->thrown_exists; ··· 5419 5490 return js_mkerr_typed(js, JS_ERR_TYPE, "Function.prototype.toString requires that 'this' be a Function"); 5420 5491 } 5421 5492 5422 - if (t == T_CFUNC) return ANT_STRING("function() { [native code] }"); 5493 + // TODO: make dry 5494 + if (t == T_CFUNC) { 5495 + ant_offset_t name_len = 0; 5496 + const char *name = get_func_name(js, func, &name_len); 5497 + if (name && name_len > 0) { 5498 + size_t total = 9 + name_len + 21 + 1; 5499 + char *buf = ant_calloc(total); 5500 + size_t n = 0; 5501 + n += cpy(buf + n, total - n, "function ", 9); 5502 + n += cpy(buf + n, total - n, name, name_len); 5503 + n += cpy(buf + n, total - n, "() { [native code] }", 20); 5504 + ant_value_t result = js_mkstr(js, buf, n); 5505 + free(buf); 5506 + return result; 5507 + } 5508 + return ANT_STRING("function() { [native code] }"); 5509 + } 5423 5510 5424 5511 ant_value_t func_obj = js_func_obj(func); 5425 5512 ant_value_t cfunc_slot = get_slot(func_obj, SLOT_CFUNC); 5426 5513 5514 + // TODO: make dry 5427 5515 if (vtype(cfunc_slot) == T_CFUNC) { 5428 5516 ant_offset_t name_len = 0; 5429 5517 const char *name = get_func_name(js, func, &name_len); ··· 5444 5532 ant_value_t code_val = get_slot(func_obj, SLOT_CODE); 5445 5533 ant_value_t len_val = get_slot(func_obj, SLOT_CODE_LEN); 5446 5534 5447 - if (vtype(code_val) == T_CFUNC && vtype(len_val) == T_NUM) { 5535 + if (vtype(code_val) == T_NTARG && vtype(len_val) == T_NUM) { 5448 5536 const char *code = (const char *)(uintptr_t)vdata(code_val); 5449 5537 size_t code_len = (size_t)tod(len_val); 5450 5538 ··· 5578 5666 if (is_err(bound_func)) return bound_func; 5579 5667 5580 5668 ant_value_t code_val = get_slot(func_obj, SLOT_CODE); 5581 - if (vtype(code_val) == T_STR || vtype(code_val) == T_CFUNC) { 5669 + if (vtype(code_val) == T_STR || vtype(code_val) == T_NTARG) { 5582 5670 set_slot(bound_func, SLOT_CODE, code_val); 5583 5671 set_slot(bound_func, SLOT_CODE_LEN, get_slot(func_obj, SLOT_CODE_LEN)); 5584 5672 } ··· 7032 7120 if (vtype(inspect_fn) == T_CFUNC) { 7033 7121 ant_value_t saved_this = js->this_val; 7034 7122 js->this_val = obj; 7035 - result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(inspect_fn))(js, &depth_arg, 1); 7123 + result = js_as_cfunc(inspect_fn)(js, &depth_arg, 1); 7036 7124 js->this_val = saved_this; 7037 - } else { 7038 - result = sv_vm_call(js->vm, js, inspect_fn, obj, &depth_arg, 1, NULL, false); 7039 - } 7125 + } else result = sv_vm_call(js->vm, js, inspect_fn, obj, &depth_arg, 1, NULL, false); 7040 7126 7041 7127 if (is_err(result) || js->thrown_exists || vtype(result) != T_STR) { 7042 7128 js_restore_exception(js, &saved); ··· 7332 7418 ant_value_t key = args[1]; 7333 7419 uint8_t t = vtype(obj); 7334 7420 7421 + if (t == T_CFUNC) { 7422 + bool is_sym = (vtype(key) == T_SYMBOL); 7423 + if (is_sym) return js_mkundef(); 7424 + 7425 + const char *key_str = NULL; 7426 + ant_offset_t key_len = 0; 7427 + if (vtype(key) == T_STR) { 7428 + ant_offset_t key_off = vstr(js, key, &key_len); 7429 + key_str = (const char *)(uintptr_t)key_off; 7430 + } else { 7431 + char buf[64]; 7432 + size_t n = tostr(js, key, buf, sizeof(buf)); 7433 + key = js_mkstr(js, buf, n); 7434 + ant_offset_t key_off = vstr(js, key, &key_len); 7435 + key_str = (const char *)(uintptr_t)key_off; 7436 + } 7437 + 7438 + ant_value_t value = js_mkundef(); 7439 + if (!js_cfunc_try_get_own(js, obj, key_str, (size_t)key_len, &value)) return js_mkundef(); 7440 + 7441 + ant_value_t result = js_mkobj(js); 7442 + js_setprop(js, result, js_mkstr(js, "value", 5), value); 7443 + js_setprop(js, result, js_mkstr(js, "writable", 8), js_false); 7444 + js_setprop(js, result, js_mkstr(js, "enumerable", 10), js_false); 7445 + js_setprop(js, result, js_mkstr(js, "configurable", 12), js_true); 7446 + 7447 + return result; 7448 + } 7449 + 7335 7450 if (t != T_OBJ && t != T_ARR && t != T_FUNC) return js_mkundef(); 7336 7451 7337 7452 const char *key_str; ··· 7429 7544 prop_val = tov((double)get_array_length(js, as_obj)); 7430 7545 has_value_out = true; 7431 7546 } 7432 - if (has_value_out) js_setprop(js, result, js_mkstr(js, "value", 5), prop_val); 7547 + if (has_value_out) { 7548 + if (vtype(prop_val) == T_CFUNC) prop_val = js_cfunc_promote(js, prop_val); 7549 + js_setprop(js, result, js_mkstr(js, "value", 5), prop_val); 7550 + } 7433 7551 js_setprop(js, result, js_mkstr(js, "writable", 8), js_bool(writable)); 7434 7552 js_setprop(js, result, js_mkstr(js, "enumerable", 10), js_bool(enumerable)); 7435 7553 js_setprop(js, result, js_mkstr(js, "configurable", 12), js_bool(configurable)); ··· 7455 7573 static ant_value_t builtin_object_getOwnPropertyNames(ant_t *js, ant_value_t *args, int nargs) { 7456 7574 if (nargs == 0) return mkarr(js); 7457 7575 ant_value_t obj = args[0]; 7576 + 7577 + if (vtype(obj) == T_CFUNC) { 7578 + ant_value_t arr = mkarr(js); 7579 + ant_offset_t idx = 0; 7580 + arr_set(js, arr, idx++, js->length_str); 7581 + if (vtype(js_cfunc_name_value(js, obj)) == T_STR) { 7582 + arr_set(js, arr, idx++, ANT_STRING("name")); 7583 + } 7584 + return mkval(T_ARR, vdata(arr)); 7585 + } 7458 7586 7459 7587 if (vtype(obj) != T_OBJ && vtype(obj) != T_ARR && vtype(obj) != T_FUNC) return mkarr(js); 7460 7588 if (vtype(obj) == T_FUNC) obj = js_func_obj(obj); ··· 11236 11364 11237 11365 GC_ROOT_PIN(js, obj); 11238 11366 set_slot(obj, SLOT_DATA, data); 11239 - set_slot(obj, SLOT_CFUNC, js_mkfun(fn)); 11367 + set_slot(obj, SLOT_CFUNC, js_mkfun_dyn(fn)); 11240 11368 11241 11369 ant_value_t func = js_obj_to_func(obj); 11242 11370 GC_ROOT_RESTORE(js, root_mark); ··· 11415 11543 11416 11544 ant_value_t res = js_mkundef(); 11417 11545 if (vtype(handler) == T_CFUNC) { 11418 - ant_value_t (*fn)(ant_t *, ant_value_t *, int) = (ant_value_t(*)(ant_t *, ant_value_t *, int))vdata(handler); 11546 + ant_value_t (*fn)(ant_t *, ant_value_t *, int) = js_as_cfunc(handler); 11419 11547 res = fn(js, &val, 1); 11420 11548 } else { 11421 11549 ant_value_t call_args[] = { val }; ··· 12629 12757 } 12630 12758 12631 12759 static ant_value_t handle_cfunc_instanceof(ant_value_t l, ant_value_t r, uint8_t ltype) { 12632 - ant_value_t (*fn)(ant_t *, ant_value_t *, int) = (ant_value_t(*)(ant_t *, ant_value_t *, int)) vdata(r); 12760 + ant_value_t (*fn)(ant_t *, ant_value_t *, int) = js_as_cfunc(r); 12633 12761 12634 12762 if (fn == builtin_Object) return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 12635 12763 if (fn == builtin_Function) return mkval(T_BOOL, (ltype == T_FUNC || ltype == T_CFUNC) ? 1 : 0); ··· 14064 14192 defmethod(js, number_ctor_obj, "isFinite", 8, js_mkfun(builtin_Number_isFinite)); 14065 14193 defmethod(js, number_ctor_obj, "isInteger", 9, js_mkfun(builtin_Number_isInteger)); 14066 14194 defmethod(js, number_ctor_obj, "isSafeInteger", 13, js_mkfun(builtin_Number_isSafeInteger)); 14067 - defmethod(js, number_ctor_obj, "parseInt", 8, js_mkfun(builtin_parseInt)); 14068 - defmethod(js, number_ctor_obj, "parseFloat", 10, js_mkfun(builtin_parseFloat)); 14195 + ant_value_t number_parse_int = defmethod(js, number_ctor_obj, "parseInt", 8, js_mkfun(builtin_parseInt)); 14196 + ant_value_t number_parse_float = defmethod(js, number_ctor_obj, "parseFloat", 10, js_mkfun(builtin_parseFloat)); 14069 14197 14070 14198 js_setprop(js, number_ctor_obj, js_mkstr(js, "MAX_VALUE", 9), tov(1.7976931348623157e+308)); 14071 14199 js_setprop(js, number_ctor_obj, js_mkstr(js, "MIN_VALUE", 9), tov(5e-324)); ··· 14127 14255 js_setprop(js, p_ctor_obj, ANT_STRING("name"), ANT_STRING("Promise")); 14128 14256 js_setprop(js, glob, js_mkstr(js, "Promise", 7), js_obj_to_func(p_ctor_obj)); 14129 14257 14130 - defmethod(js, glob, "parseInt", 8, js_mkfun(builtin_parseInt)); 14131 - defmethod(js, glob, "parseFloat", 10, js_mkfun(builtin_parseFloat)); 14258 + defalias(js, glob, "parseInt", 8, number_parse_int); 14259 + defalias(js, glob, "parseFloat", 10, number_parse_float); 14132 14260 defmethod(js, glob, "eval", 4, js_mkfun(builtin_eval)); 14133 14261 defmethod(js, glob, "isNaN", 5, js_mkfun(builtin_global_isNaN)); 14134 14262 defmethod(js, glob, "isFinite", 8, js_mkfun(builtin_global_isFinite)); ··· 14235 14363 js->cfunc_promote_cache.promoted = NULL; 14236 14364 js->cfunc_promote_cache.len = js->cfunc_promote_cache.cap = 0; 14237 14365 14366 + for (uint16_t i = 0; i < js->cfunc_name_cache.len; i++) free( 14367 + (void *)(uintptr_t)vdata(js->cfunc_name_cache.named[i]) 14368 + ); 14369 + 14370 + free(js->cfunc_name_cache.base_meta); 14371 + free(js->cfunc_name_cache.name_ptr); 14372 + free(js->cfunc_name_cache.named); 14373 + 14374 + js->cfunc_name_cache.base_meta = NULL; 14375 + js->cfunc_name_cache.name_ptr = NULL; 14376 + js->cfunc_name_cache.named = NULL; 14377 + js->cfunc_name_cache.len = js->cfunc_name_cache.cap = 0; 14378 + 14238 14379 js_pool_destroy(&js->pool.rope); 14239 14380 js_pool_destroy(&js->pool.symbol); 14240 14381 js_pool_destroy(&js->pool.permanent); ··· 14256 14397 inline ant_value_t js_mknum(double value) { return tov(value); } 14257 14398 inline ant_value_t js_mkobj(ant_t *js) { return mkobj(js, 0); } 14258 14399 inline ant_value_t js_glob(ant_t *js) { return js->global; } 14259 - inline ant_value_t js_mkfun(ant_value_t (*fn)(ant_t *, ant_value_t *, int)) { return mkval(T_CFUNC, (size_t) (void *) fn); } 14400 + 14401 + ant_value_t js_mkfun_meta(const ant_cfunc_meta_t *meta) { 14402 + return mkval(T_CFUNC, (uintptr_t)meta); 14403 + } 14404 + 14405 + ant_value_t js_mkfun_dyn(ant_cfunc_t fn) { 14406 + typedef struct dyn_cfunc_meta_entry { 14407 + ant_cfunc_t fn; 14408 + ant_cfunc_meta_t meta; 14409 + struct dyn_cfunc_meta_entry *next; 14410 + } dyn_cfunc_meta_entry_t; 14411 + 14412 + static dyn_cfunc_meta_entry_t *head = NULL; 14413 + for (dyn_cfunc_meta_entry_t *it = head; it; it = it->next) { 14414 + if (it->fn == fn) return js_mkfun_meta(&it->meta); 14415 + } 14416 + 14417 + dyn_cfunc_meta_entry_t *entry = ant_calloc(sizeof(dyn_cfunc_meta_entry_t)); 14418 + if (!entry) return mkval(T_ERR, 0); 14419 + 14420 + entry->fn = fn; 14421 + entry->meta.fn = fn; 14422 + entry->next = head; 14423 + head = entry; 14424 + 14425 + return js_mkfun_meta(&entry->meta); 14426 + } 14260 14427 14261 14428 inline ant_value_t js_getthis(ant_t *js) { return js->this_val; } 14262 14429 inline void js_setthis(ant_t *js, ant_value_t val) { js->this_val = val; } 14263 14430 inline ant_value_t js_getcurrentfunc(ant_t *js) { return js->current_func; } 14264 14431 14432 + static ant_value_t js_cfunc_name_value(ant_t *js, ant_value_t cfunc) { 14433 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(cfunc); 14434 + if (!meta || !meta->name) return js_mkundef(); 14435 + return js_mkstr(js, meta->name, strlen(meta->name)); 14436 + } 14437 + 14438 + static ant_value_t js_cfunc_length_value(ant_value_t cfunc) { 14439 + return tov((double)js_cfunc_length(cfunc)); 14440 + } 14441 + 14442 + ant_value_t js_cfunc_expose_named(ant_t *js, ant_value_t cfunc, const char *name, size_t name_len) { 14443 + if (vtype(cfunc) != T_CFUNC || !name || is_internal_prop(name, (ant_offset_t)name_len)) return cfunc; 14444 + 14445 + const ant_cfunc_meta_t *base = js_as_cfunc_meta(cfunc); 14446 + if (!base) return cfunc; 14447 + 14448 + if ( 14449 + base->name && 14450 + strlen(base->name) == name_len && 14451 + memcmp(base->name, name, name_len) == 0 14452 + ) return cfunc; 14453 + 14454 + const char *interned = intern_string(name, name_len); 14455 + if (!interned) return js_mkerr(js, "oom"); 14456 + 14457 + for (uint16_t i = 0; i < js->cfunc_name_cache.len; i++) if ( 14458 + js->cfunc_name_cache.base_meta[i] == base && 14459 + js->cfunc_name_cache.name_ptr[i] == interned 14460 + ) return js->cfunc_name_cache.named[i]; 14461 + 14462 + ant_cfunc_meta_t *named_meta = ant_calloc(sizeof(ant_cfunc_meta_t)); 14463 + if (!named_meta) return js_mkerr(js, "oom"); 14464 + 14465 + named_meta->fn = base->fn; 14466 + named_meta->name = interned; 14467 + named_meta->length = base->length; 14468 + named_meta->flags = base->flags; 14469 + 14470 + if (js->cfunc_name_cache.len >= js->cfunc_name_cache.cap) { 14471 + uint16_t new_cap = js->cfunc_name_cache.cap ? js->cfunc_name_cache.cap * 2 : 8; 14472 + 14473 + const ant_cfunc_meta_t **new_base = realloc( 14474 + js->cfunc_name_cache.base_meta, 14475 + new_cap * sizeof(ant_cfunc_meta_t *) 14476 + ); 14477 + 14478 + const char **new_names = realloc(js->cfunc_name_cache.name_ptr, new_cap * sizeof(const char *)); 14479 + ant_value_t *new_named = realloc(js->cfunc_name_cache.named, new_cap * sizeof(ant_value_t)); 14480 + 14481 + if (!new_base || !new_names || !new_named) { 14482 + free(named_meta); 14483 + return js_mkerr(js, "oom"); 14484 + } 14485 + 14486 + js->cfunc_name_cache.base_meta = new_base; 14487 + js->cfunc_name_cache.name_ptr = new_names; 14488 + js->cfunc_name_cache.named = new_named; 14489 + js->cfunc_name_cache.cap = new_cap; 14490 + } 14491 + 14492 + ant_value_t named = js_mkfun_meta(named_meta); 14493 + uint16_t idx = js->cfunc_name_cache.len++; 14494 + js->cfunc_name_cache.base_meta[idx] = base; 14495 + js->cfunc_name_cache.name_ptr[idx] = interned; 14496 + js->cfunc_name_cache.named[idx] = named; 14497 + 14498 + return named; 14499 + } 14500 + 14501 + static ant_value_t js_expose_cfunc_for_key(ant_t *js, ant_value_t value, const char *key, size_t key_len) { 14502 + if (vtype(value) != T_CFUNC) return value; 14503 + return js_cfunc_expose_named(js, value, key, key_len); 14504 + } 14505 + 14265 14506 ant_value_t js_cfunc_promote(ant_t *js, ant_value_t cfunc) { 14266 14507 uintptr_t ptr = vdata(cfunc); 14508 + const ant_cfunc_meta_t *meta = js_as_cfunc_meta(cfunc); 14267 14509 14268 14510 for (uint8_t i = 0; i < js->cfunc_promote_cache.len; i++) { 14269 14511 if (js->cfunc_promote_cache.cfunc_ptr[i] == ptr) ··· 14279 14521 if (obj_ptr) obj_ptr->proto = proto; 14280 14522 } 14281 14523 14524 + ant_value_t length_result = js_setprop(js, fn_obj, ANT_STRING("length"), js_cfunc_length_value(cfunc)); 14525 + if (is_err(length_result)) return length_result; 14526 + js_set_descriptor(js, fn_obj, "length", 6, JS_DESC_C); 14527 + 14528 + if (meta && meta->name) { 14529 + ant_value_t name_result = js_setprop(js, fn_obj, ANT_STRING("name"), js_cfunc_name_value(js, cfunc)); 14530 + if (is_err(name_result)) return name_result; 14531 + js_set_descriptor(js, fn_obj, "name", 4, JS_DESC_C); 14532 + } 14533 + 14282 14534 ant_value_t promoted = js_obj_to_func(fn_obj); 14283 14535 14284 14536 if (js->cfunc_promote_cache.len >= js->cfunc_promote_cache.cap) { ··· 14303 14555 } 14304 14556 14305 14557 ant_value_t js_heavy_mkfun(ant_t *js, ant_value_t (*fn)(ant_t *, ant_value_t *, int), ant_value_t data) { 14306 - ant_value_t cfunc = js_mkfun(fn); 14558 + ant_value_t cfunc = js_mkfun_dyn(fn); 14307 14559 ant_value_t fn_obj = mkobj(js, 0); 14308 14560 14309 14561 set_slot(fn_obj, SLOT_CFUNC, cfunc); ··· 14314 14566 14315 14567 void js_set(ant_t *js, ant_value_t obj, const char *key, ant_value_t val) { 14316 14568 size_t key_len = strlen(key); 14569 + val = js_expose_cfunc_for_key(js, val, key, key_len); 14570 + if (is_err(val)) return; 14317 14571 14318 14572 if (vtype(obj) == T_OBJ) { 14319 14573 ant_offset_t existing = lkp(js, obj, key, key_len); ··· 14343 14597 } 14344 14598 } 14345 14599 14600 + void js_set_exact(ant_t *js, ant_value_t obj, const char *key, ant_value_t val) { 14601 + size_t key_len = strlen(key); 14602 + const char *interned = intern_string(key, key_len); 14603 + 14604 + if (!interned) { 14605 + js_mkerr(js, "oom"); 14606 + return; 14607 + } 14608 + 14609 + if (vtype(obj) == T_OBJ) { 14610 + ant_offset_t existing = lkp(js, obj, key, key_len); 14611 + if (existing > 0) { 14612 + if (is_const_prop(js, existing)) { 14613 + js_mkerr(js, "assignment to constant"); 14614 + return; 14615 + } 14616 + js_saveval(js, existing, val); 14617 + } else mkprop_interned_exact(js, obj, interned, val, 0); 14618 + } else if (vtype(obj) == T_FUNC) { 14619 + ant_value_t func_obj = js_func_obj(obj); 14620 + ant_offset_t existing = lkp(js, func_obj, key, key_len); 14621 + if (existing > 0) { 14622 + if (is_const_prop(js, existing)) { 14623 + js_mkerr(js, "assignment to constant"); 14624 + return; 14625 + } 14626 + js_saveval(js, existing, val); 14627 + } else mkprop_interned_exact(js, func_obj, interned, val, 0); 14628 + } 14629 + } 14630 + 14346 14631 void js_set_sym(ant_t *js, ant_value_t obj, ant_value_t sym, ant_value_t val) { 14347 14632 if (vtype(sym) != T_SYMBOL) return; 14348 14633 ant_offset_t sym_off = (ant_offset_t)vdata(sym); ··· 14423 14708 14424 14709 static bool js_try_get(ant_t *js, ant_value_t obj, const char *key, ant_value_t *out) { 14425 14710 size_t key_len = strlen(key); 14711 + 14712 + if (vtype(obj) == T_CFUNC) { 14713 + if (js_cfunc_try_get_own(js, obj, key, key_len, out)) return true; 14714 + ant_offset_t off = lkp_proto(js, obj, key, key_len); 14715 + if (off != 0) { 14716 + *out = propref_load(js, off); 14717 + return true; 14718 + } 14719 + return false; 14720 + } 14426 14721 14427 14722 if (vtype(obj) == T_FUNC) { 14428 14723 if (sv_vm_is_strict(js->vm) && ··· 14441 14736 if (vtype(import_meta) == T_UNDEF) import_meta = js_get_current_import_meta(js); 14442 14737 if (key_len == 4 && memcmp(key, "meta", 4) == 0 && vtype(import_meta) != T_UNDEF) { 14443 14738 ant_value_t cfunc = js_get_slot(func_obj, SLOT_CFUNC); 14444 - if (vtype(cfunc) == T_CFUNC && js_as_cfunc(cfunc) == js_builtin_import) { 14739 + if (vtype(cfunc) == T_CFUNC && js_cfunc_same_entrypoint(cfunc, js_builtin_import)) { 14445 14740 *out = import_meta; 14446 14741 return true; 14447 14742 } ··· 14596 14891 } 14597 14892 14598 14893 ant_value_t js_getprop_fallback(ant_t *js, ant_value_t obj, const char *name) { 14599 - if (vtype(obj) == T_CFUNC && js->cfunc_promote_cache.len > 0) { 14600 - ant_value_t promoted = js_cfunc_lookup_promoted(js, obj); 14601 - if (vtype(promoted) != T_CFUNC) return js_getprop_fallback(js, promoted, name); 14602 - } 14603 - 14604 14894 ant_value_t val; 14605 14895 if (js_try_get(js, obj, name, &val)) return val; 14606 14896
+4 -5
src/modules/buffer.c
··· 2601 2601 js_set(js, g_typedarray_iter_proto, "next", js_mkfun(ta_iter_next)); 2602 2602 js_iter_register_advance(g_typedarray_iter_proto, advance_typedarray); 2603 2603 2604 - ant_value_t ta_values_fn = js_mkfun(ta_values); 2605 - js_set(js, typedarray_proto, "values", ta_values_fn); 2604 + js_set(js, typedarray_proto, "values", js_mkfun(ta_values)); 2606 2605 js_set(js, typedarray_proto, "keys", js_mkfun(ta_keys)); 2607 2606 js_set(js, typedarray_proto, "entries", js_mkfun(ta_entries)); 2608 - js_set_sym(js, typedarray_proto, get_iterator_sym(), ta_values_fn); 2607 + js_set_sym(js, typedarray_proto, get_iterator_sym(), js_get(js, typedarray_proto, "values")); 2609 2608 2610 2609 #define SETUP_TYPEDARRAY(name) \ 2611 2610 do { \ ··· 2709 2708 js_set(js, buffer_proto, "readUInt32BE", js_mkfun(js_buffer_readUInt32BE)); 2710 2709 2711 2710 js_set_sym(js, buffer_proto, get_toStringTag_sym(), js_mkstr(js, "Buffer", 6)); 2712 - js_set_sym(js, buffer_proto, get_iterator_sym(), ta_values_fn); 2713 - js_set(js, buffer_proto, "values", ta_values_fn); 2711 + js_set(js, buffer_proto, "values", js_get(js, typedarray_proto, "values")); 2712 + js_set_sym(js, buffer_proto, get_iterator_sym(), js_get(js, buffer_proto, "values")); 2714 2713 2715 2714 js_set(js, buffer_ctor_obj, "from", js_mkfun(js_buffer_from)); 2716 2715 js_set(js, buffer_ctor_obj, "alloc", js_mkfun(js_buffer_alloc));
+3 -13
src/modules/collections.c
··· 513 513 return create_map_iterator(js, js->this_val, ITER_TYPE_MAP_ENTRIES); 514 514 } 515 515 516 - static ant_value_t map_iterator(ant_t *js, ant_value_t *args, int nargs) { 517 - (void)args; (void)nargs; 518 - return create_map_iterator(js, js->this_val, ITER_TYPE_MAP_ENTRIES); 519 - } 520 - 521 516 bool advance_set(ant_t *js, js_iter_t *it, ant_value_t *out) { 522 517 set_iterator_state_t *state = get_set_iter_state(js, it->iterator); 523 518 if (!state || !state->current) return false; ··· 636 631 static ant_value_t set_entries(ant_t *js, ant_value_t *args, int nargs) { 637 632 (void)args; (void)nargs; 638 633 return create_set_iterator(js, js->this_val, ITER_TYPE_SET_ENTRIES); 639 - } 640 - 641 - static ant_value_t set_iterator(ant_t *js, ant_value_t *args, int nargs) { 642 - (void)args; (void)nargs; 643 - return create_set_iterator(js, js->this_val, ITER_TYPE_SET_VALUES); 644 634 } 645 635 646 636 static ant_value_t set_forEach(ant_t *js, ant_value_t *args, int nargs) { ··· 1106 1096 js_set(js, map_proto, "keys", js_mkfun(map_keys)); 1107 1097 js_set(js, map_proto, "values", js_mkfun(map_values)); 1108 1098 js_set(js, map_proto, "forEach", js_mkfun(map_forEach)); 1109 - js_set_sym(js, map_proto, iter_sym, js_mkfun(map_iterator)); 1099 + js_set_sym(js, map_proto, iter_sym, js_get(js, map_proto, "entries")); 1110 1100 js_set_sym(js, map_proto, tag_sym, js_mkstr(js, "Map", 3)); 1111 1101 1112 1102 ant_value_t map_ctor = js_mkobj(js); ··· 1126 1116 js_set(js, set_proto, "clear", js_mkfun(set_clear)); 1127 1117 js_set_getter_desc(js, set_proto, "size", 4, js_mkfun(set_size), JS_DESC_C); 1128 1118 js_set(js, set_proto, "values", js_mkfun(set_values)); 1129 - js_set(js, set_proto, "keys", js_mkfun(set_values)); 1119 + js_set_exact(js, set_proto, "keys", js_get(js, set_proto, "values")); 1130 1120 js_set(js, set_proto, "entries", js_mkfun(set_entries)); 1131 1121 js_set(js, set_proto, "forEach", js_mkfun(set_forEach)); 1132 - js_set_sym(js, set_proto, iter_sym, js_mkfun(set_iterator)); 1122 + js_set_sym(js, set_proto, iter_sym, js_get(js, set_proto, "values")); 1133 1123 js_set_sym(js, set_proto, tag_sym, js_mkstr(js, "Set", 3)); 1134 1124 1135 1125 ant_value_t set_ctor = js_mkobj(js);
+1 -1
src/modules/date.c
··· 1280 1280 ) { 1281 1281 for (size_t i = 0; i < count; i++) js_setprop(js,target, 1282 1282 js_mkstr(js, methods[i].name, methods[i].len), 1283 - js_mkfun(methods[i].fn) 1283 + js_mkfun_dyn(methods[i].fn) 1284 1284 ); 1285 1285 } 1286 1286
+2 -2
src/modules/events.c
··· 1253 1253 if (is_object_type(function_proto)) js_set_proto_init(eventemitter_ctor, function_proto); 1254 1254 1255 1255 js_set(js, eventemitter_proto, "on", js_mkfun(js_eventemitter_on)); 1256 - js_set(js, eventemitter_proto, "addListener", js_mkfun(js_eventemitter_on)); 1256 + js_set_exact(js, eventemitter_proto, "addListener", js_get(js, eventemitter_proto, "on")); 1257 1257 js_set(js, eventemitter_proto, "once", js_mkfun(js_eventemitter_once)); 1258 1258 js_set(js, eventemitter_proto, "prependListener", js_mkfun(js_eventemitter_prepend_listener)); 1259 1259 js_set(js, eventemitter_proto, "prependOnceListener", js_mkfun(js_eventemitter_prepend_once_listener)); 1260 1260 js_set(js, eventemitter_proto, "off", js_mkfun(js_eventemitter_off)); 1261 - js_set(js, eventemitter_proto, "removeListener", js_mkfun(js_eventemitter_off)); 1261 + js_set_exact(js, eventemitter_proto, "removeListener", js_get(js, eventemitter_proto, "off")); 1262 1262 js_set(js, eventemitter_proto, "emit", js_mkfun(js_eventemitter_emit)); 1263 1263 js_set(js, eventemitter_proto, "removeAllListeners", js_mkfun(js_eventemitter_removeAllListeners)); 1264 1264 js_set(js, eventemitter_proto, "listenerCount", js_mkfun(js_eventemitter_listenerCount));
+1 -1
src/modules/formdata.c
··· 487 487 js_set(js, g_formdata_proto, "keys", js_mkfun(js_formdata_keys)); 488 488 js_set(js, g_formdata_proto, "values", js_mkfun(js_formdata_values)); 489 489 490 - js_set_sym(js, g_formdata_proto, get_iterator_sym(), js_mkfun(js_formdata_entries)); 490 + js_set_sym(js, g_formdata_proto, get_iterator_sym(), js_get(js, g_formdata_proto, "entries")); 491 491 js_set_sym(js, g_formdata_proto, get_toStringTag_sym(), js_mkstr(js, "FormData", 8)); 492 492 493 493 ant_value_t ctor_obj = js_mkobj(js);
+1 -2
src/modules/fs.c
··· 191 191 ant_value_t result = js_mkundef(); 192 192 193 193 js->this_val = this_val; 194 - if (vtype(fn) == T_CFUNC) 195 - result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(fn))(js, args, nargs); 194 + if (vtype(fn) == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs); 196 195 else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); 197 196 js->this_val = saved_this; 198 197
+1 -5
src/modules/headers.c
··· 725 725 return make_headers_iter(js, js->this_val, ITER_ENTRIES); 726 726 } 727 727 728 - static ant_value_t js_headers_symbol_iterator(ant_t *js, ant_value_t *args, int nargs) { 729 - return make_headers_iter(js, js->this_val, ITER_ENTRIES); 730 - } 731 - 732 728 static ant_value_t headers_inspect_finish(ant_t *js, ant_value_t this_obj, ant_value_t body_obj) { 733 729 ant_value_t tag_val = js_get_sym(js, this_obj, get_toStringTag_sym()); 734 730 const char *tag = vtype(tag_val) == T_STR ? js_getstr(js, tag_val, NULL) : "Headers"; ··· 1095 1091 js_set(js, g_headers_proto, "entries", js_mkfun(js_headers_entries)); 1096 1092 js_set(js, g_headers_proto, "getSetCookie", js_mkfun(js_headers_get_set_cookie)); 1097 1093 1098 - js_set_sym(js, g_headers_proto, get_iterator_sym(), js_mkfun(js_headers_symbol_iterator)); 1094 + js_set_sym(js, g_headers_proto, get_iterator_sym(), js_get(js, g_headers_proto, "entries")); 1099 1095 js_set_sym(js, g_headers_proto, get_inspect_sym(), js_mkfun(headers_inspect)); 1100 1096 js_set_sym(js, g_headers_proto, get_toStringTag_sym(), js_mkstr(js, "Headers", 7)); 1101 1097
+1 -1
src/modules/io.c
··· 397 397 ant_value_t result = js_mkundef(); 398 398 399 399 js->this_val = this_val; 400 - if (vtype(fn) == T_CFUNC) result = ((ant_cfunc_t)vdata(fn))(js, args, nargs); 400 + if (vtype(fn) == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs); 401 401 else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); 402 402 js->this_val = saved_this; 403 403
+1 -2
src/modules/net.c
··· 151 151 ant_value_t result = js_mkundef(); 152 152 153 153 js->this_val = this_val; 154 - if (vtype(fn) == T_CFUNC) 155 - result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(fn))(js, args, nargs); 154 + if (vtype(fn) == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs); 156 155 else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); 157 156 js->this_val = saved_this; 158 157 return result;
+5 -5
src/modules/process.c
··· 1845 1845 1846 1846 if (include_event_methods) { 1847 1847 js_set(js, obj, "on", js_mkfun(process_on)); 1848 - js_set(js, obj, "addListener", js_mkfun(process_on)); 1848 + js_set_exact(js, obj, "addListener", js_get(js, obj, "on")); 1849 1849 js_set(js, obj, "once", js_mkfun(process_once)); 1850 1850 js_set(js, obj, "prependListener", js_mkfun(process_prepend_listener)); 1851 1851 js_set(js, obj, "prependOnceListener", js_mkfun(process_prepend_once_listener)); 1852 1852 js_set(js, obj, "off", js_mkfun(process_off)); 1853 - js_set(js, obj, "removeListener", js_mkfun(process_off)); 1853 + js_set_exact(js, obj, "removeListener", js_get(js, obj, "off")); 1854 1854 js_set(js, obj, "removeAllListeners", js_mkfun(process_remove_all_listeners)); 1855 1855 js_set(js, obj, "emit", js_mkfun(process_emit)); 1856 1856 js_set(js, obj, "listenerCount", js_mkfun(process_listener_count)); ··· 1967 1967 js_set(js, stdin_proto, "resume", js_mkfun(js_stdin_resume)); 1968 1968 js_set(js, stdin_proto, "pause", js_mkfun(js_stdin_pause)); 1969 1969 js_set(js, stdin_proto, "on", js_mkfun(js_stdin_on)); 1970 - js_set(js, stdin_proto, "removeListener", js_mkfun(js_stdin_remove_listener)); 1971 1970 js_set(js, stdin_proto, "off", js_mkfun(js_stdin_remove_listener)); 1971 + js_set_exact(js, stdin_proto, "removeListener", js_get(js, stdin_proto, "off")); 1972 1972 js_set(js, stdin_proto, "removeAllListeners", js_mkfun(js_stdin_remove_all_listeners)); 1973 1973 js_set_sym(js, stdin_proto, get_toStringTag_sym(), js_mkstr(js, "ReadStream", 10)); 1974 1974 ··· 1982 1982 js_set(js, stdout_proto, "write", js_mkfun(js_stdout_write)); 1983 1983 js_set(js, stdout_proto, "on", js_mkfun(js_stdout_on)); 1984 1984 js_set(js, stdout_proto, "once", js_mkfun(js_stdout_once)); 1985 - js_set(js, stdout_proto, "removeListener", js_mkfun(js_stdout_remove_listener)); 1986 1985 js_set(js, stdout_proto, "off", js_mkfun(js_stdout_remove_listener)); 1986 + js_set_exact(js, stdout_proto, "removeListener", js_get(js, stdout_proto, "off")); 1987 1987 js_set(js, stdout_proto, "removeAllListeners", js_mkfun(js_stdout_remove_all_listeners)); 1988 1988 js_set(js, stdout_proto, "getWindowSize", js_mkfun(js_stdout_get_window_size)); 1989 1989 js_set_sym(js, stdout_proto, get_toStringTag_sym(), js_mkstr(js, "WriteStream", 11)); ··· 1999 1999 js_set(js, stderr_proto, "write", js_mkfun(js_stderr_write)); 2000 2000 js_set(js, stderr_proto, "on", js_mkfun(js_stderr_on)); 2001 2001 js_set(js, stderr_proto, "once", js_mkfun(js_stderr_once)); 2002 - js_set(js, stderr_proto, "removeListener", js_mkfun(js_stderr_remove_listener)); 2003 2002 js_set(js, stderr_proto, "off", js_mkfun(js_stderr_remove_listener)); 2003 + js_set_exact(js, stderr_proto, "removeListener", js_get(js, stderr_proto, "off")); 2004 2004 js_set(js, stderr_proto, "removeAllListeners", js_mkfun(js_stderr_remove_all_listeners)); 2005 2005 js_set_sym(js, stderr_proto, get_toStringTag_sym(), js_mkstr(js, "WriteStream", 11)); 2006 2006
+2 -2
src/modules/regex.c
··· 1054 1054 ant_value_t *out_result 1055 1055 ) { 1056 1056 if (!out_result || vtype(call_func) != T_CFUNC) return false; 1057 - if (js_as_cfunc(call_func) != builtin_regexp_exec) return false; 1057 + if (!js_cfunc_same_entrypoint(call_func, builtin_regexp_exec)) return false; 1058 1058 if (!is_object_type(regexp) || vtype(arg) != T_STR) return false; 1059 1059 1060 1060 ant_value_t result = regexp_exec_internal(js, regexp, arg, true); ··· 1077 1077 if (is_err(exec_fn)) return exec_fn; 1078 1078 1079 1079 ant_value_t result; 1080 - if (vtype(exec_fn) == T_CFUNC && js_as_cfunc(exec_fn) == builtin_regexp_exec) { 1080 + if (vtype(exec_fn) == T_CFUNC && js_cfunc_same_entrypoint(exec_fn, builtin_regexp_exec)) { 1081 1081 result = regexp_exec_internal(js, regexp, str_arg, true); 1082 1082 } else result = regexp_exec_with_exec_fn(js, regexp, str_arg, exec_fn); 1083 1083
+2 -2
src/modules/server.c
··· 285 285 ant_value_t result = js_mkundef(); 286 286 287 287 js->this_val = server->export_obj; 288 - if (vtype(server->fetch_fn) == T_CFUNC) 289 - result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(server->fetch_fn))(js, args, 2); 288 + if (vtype(server->fetch_fn) == T_CFUNC) result = js_as_cfunc(server->fetch_fn)(js, args, 2); 290 289 else result = sv_vm_call(js->vm, js, server->fetch_fn, server->export_obj, args, 2, NULL, false); 291 290 js->this_val = saved_this; 291 + 292 292 return result; 293 293 } 294 294
+3 -3
src/modules/url.c
··· 1437 1437 js_set(js, g_usp_proto, "forEach", js_mkfun(usp_forEach)); 1438 1438 js_set_getter_desc(js, g_usp_proto, "size", 4, js_mkfun(usp_size_get), JS_DESC_C); 1439 1439 1440 - ant_value_t entries_fn = js_mkfun(usp_entries_fn); 1441 - js_set(js, g_usp_proto, "entries", entries_fn); 1440 + js_set(js, g_usp_proto, "entries", js_mkfun(usp_entries_fn)); 1442 1441 js_set(js, g_usp_proto, "keys", js_mkfun(usp_keys_fn)); 1443 1442 js_set(js, g_usp_proto, "values", js_mkfun(usp_values_fn)); 1444 - js_set_sym(js, g_usp_proto, get_iterator_sym(), entries_fn); 1443 + 1444 + js_set_sym(js, g_usp_proto, get_iterator_sym(), js_get(js, g_usp_proto, "entries")); 1445 1445 js_set_sym(js, g_usp_proto, get_toStringTag_sym(), js_mkstr(js, "URLSearchParams", 15)); 1446 1446 1447 1447 ant_value_t usp_ctor = js_make_ctor(js, js_URLSearchParams, g_usp_proto, "URLSearchParams", 15);
+7 -7
src/silver/compiler.c
··· 154 154 155 155 int child_count = 0; 156 156 for (int i = 0; i < func->const_count; i++) { 157 - if (vtype(func->constants[i]) == T_CFUNC) child_count++; 157 + if (vtype(func->constants[i]) == T_NTARG) child_count++; 158 158 } 159 159 160 160 if (child_count > 0) { ··· 162 162 if (func->child_funcs) { 163 163 int out = 0; 164 164 for (int i = 0; i < func->const_count; i++) { 165 - if (vtype(func->constants[i]) != T_CFUNC) continue; 165 + if (vtype(func->constants[i]) != T_NTARG) continue; 166 166 func->child_funcs[out++] = (sv_func_t *)(uintptr_t)vdata(func->constants[i]); 167 167 } func->child_func_count = child_count; 168 168 } ··· 1214 1214 static void hoist_one_func(sv_compiler_t *c, sv_ast_t *node) { 1215 1215 sv_func_t *fn = compile_function_body(c, node, c->mode); 1216 1216 if (!fn) return; 1217 - int idx = add_constant(c, mkval(T_CFUNC, (uintptr_t)fn)); 1217 + int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn)); 1218 1218 emit_op(c, OP_CLOSURE); 1219 1219 emit_u32(c, (uint32_t)idx); 1220 1220 emit_set_function_name(c, node->str, node->len); ··· 2543 2543 if (has_name) end_scope(c); 2544 2544 return; 2545 2545 } 2546 - int idx = add_constant(c, mkval(T_CFUNC, (uintptr_t)fn)); 2546 + 2547 + int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn)); 2547 2548 emit_op(c, OP_CLOSURE); 2548 2549 emit_u32(c, (uint32_t)idx); 2549 2550 ··· 4155 4156 fn->name = name; 4156 4157 } 4157 4158 sv_compile_ctx_cleanup(&comp); 4158 - 4159 - int idx = add_constant(c, mkval(T_CFUNC, (uintptr_t)fn)); 4159 + int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn)); 4160 4160 emit_op(c, OP_CLOSURE); 4161 4161 emit_u32(c, (uint32_t)idx); 4162 4162 } else emit_op(c, OP_UNDEF); ··· 4802 4802 fprintf(stderr, "\n"); 4803 4803 4804 4804 for (int i = 0; i < func->const_count; i++) { 4805 - if (vtype(func->constants[i]) == T_CFUNC) { 4805 + if (vtype(func->constants[i]) == T_NTARG) { 4806 4806 sv_func_t *child = (sv_func_t *)(uintptr_t)vdata(func->constants[i]); 4807 4807 char child_label[256]; 4808 4808 snprintf(child_label, sizeof(child_label), "%s/closure[%d]", label, i);
+2 -4
src/silver/engine.c
··· 1416 1416 1417 1417 if ( 1418 1418 vtype(call_func) == T_CFUNC && 1419 - js_as_cfunc(call_func) == builtin_object_isPrototypeOf 1420 - ) { 1421 - call_result = sv_isproto_ic_eval(js, call_this, call_arg, func, ip); 1422 - } else { 1419 + js_cfunc_same_entrypoint(call_func, builtin_object_isPrototypeOf) 1420 + ) call_result = sv_isproto_ic_eval(js, call_this, call_arg, func, ip); else { 1423 1421 ant_value_t call_args[1] = { call_arg }; 1424 1422 frame->ip = ip; 1425 1423 call_result = sv_vm_call(vm, js, call_func, call_this, call_args, 1, NULL, false);
+1 -4
src/silver/glue.c
··· 527 527 ) { 528 528 uint8_t *ip = NULL; 529 529 if (func && bc_off >= 0 && bc_off < func->code_len) ip = func->code + bc_off; 530 - if ( 531 - vtype(call_func) == T_CFUNC && 532 - js_as_cfunc(call_func) == builtin_object_isPrototypeOf 533 - ) { 530 + if (vtype(call_func) == T_CFUNC && js_cfunc_same_entrypoint(call_func, builtin_object_isPrototypeOf)) { 534 531 return sv_isproto_ic_eval(js, call_this, arg, func, ip); 535 532 } 536 533 ant_value_t args[1] = { arg };
-12
src/silver/ops/property.h
··· 103 103 } 104 104 105 105 *out = (idx < ptr->prop_count) ? ant_object_prop_get_unchecked(ptr, idx) : js_mkundef(); 106 - if (vtype(*out) == T_CFUNC && js->cfunc_promote_cache.len > 0) { 107 - ant_value_t promoted = js_cfunc_lookup_promoted(js, *out); 108 - if (vtype(promoted) != T_CFUNC) { 109 - ant_object_prop_set_unchecked(ptr, idx, promoted); 110 - gc_write_barrier(js, ptr, promoted); 111 - *out = promoted; 112 - }} 113 106 114 107 return true; 115 108 } ··· 280 273 sv_func_t *func, uint8_t *ip 281 274 ) { 282 275 uint8_t t = vtype(obj); 283 - 284 - if (t == T_CFUNC && js->cfunc_promote_cache.len > 0) { 285 - ant_value_t promoted = js_cfunc_lookup_promoted(js, obj); 286 - if (vtype(promoted) != T_CFUNC) return sv_prop_get_at(js, promoted, str, len, func, ip); 287 - } 288 276 289 277 if (t == T_NULL || t == T_UNDEF) { 290 278 if (func && ip) js_set_error_site_from_bc(js, func, (int)(ip - func->code), func->filename);
+2 -2
src/silver/swarm.c
··· 922 922 if (idx >= (uint32_t)func->const_count) return NULL; 923 923 924 924 ant_value_t cv = func->constants[idx]; 925 - if (vtype(cv) != T_CFUNC) return NULL; 925 + if (vtype(cv) != T_NTARG) return NULL; 926 926 927 927 return (sv_func_t *)(uintptr_t)vdata(cv); 928 928 } ··· 2020 2020 uint32_t idx = sv_get_u32(ip + 1); 2021 2021 if (idx >= (uint32_t)func->const_count) return false; 2022 2022 ant_value_t cv = func->constants[idx]; 2023 - if (vtype(cv) != T_CFUNC) return false; 2023 + if (vtype(cv) != T_NTARG) return false; 2024 2024 break; 2025 2025 } 2026 2026 case OP_RE_EXEC_TRUTHY:
+1 -1
src/streams/queuing.c
··· 76 76 static ant_value_t make_size_fn(ant_t *js, ant_cfunc_t cfunc, int length) { 77 77 ant_value_t obj = js_mkobj(js); 78 78 79 - js_set_slot(obj, SLOT_CFUNC, js_mkfun(cfunc)); 79 + js_set_slot(obj, SLOT_CFUNC, js_mkfun_dyn(cfunc)); 80 80 js_mkprop_fast(js, obj, "name", 4, js_mkstr(js, "size", 4)); 81 81 js_set_descriptor(js, obj, "name", 4, 0); 82 82 js_mkprop_fast(js, obj, "length", 6, js_mknum(length));
+149
tests/test_native_method_descriptors.cjs
··· 1 + let pass = true; 2 + const { EventEmitter } = require('events'); 3 + 4 + if ('a' + [].at !== 'afunction at() { [native code] }') { 5 + console.log('FAIL: built-in methods should stringify with their exposed property name'); 6 + pass = false; 7 + } 8 + 9 + if (fetch.name !== 'fetch') { 10 + console.log('FAIL: global native functions should expose their property name'); 11 + pass = false; 12 + } 13 + 14 + if (Number.parseInt !== globalThis.parseInt || Number.parseFloat !== globalThis.parseFloat) { 15 + console.log('FAIL: Number parse aliases should reuse the global native functions'); 16 + pass = false; 17 + } 18 + 19 + if (Function.prototype.toString.call(fetch) !== 'function fetch() { [native code] }') { 20 + console.log('FAIL: Function.prototype.toString should use the exposed global name for native functions'); 21 + pass = false; 22 + } 23 + 24 + const nameDesc = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'name'); 25 + if (!nameDesc || nameDesc.value !== 'toString') { 26 + console.log('FAIL: Function.prototype.toString should expose a name descriptor'); 27 + pass = false; 28 + } 29 + 30 + if (!nameDesc || nameDesc.writable !== false || nameDesc.enumerable !== false || nameDesc.configurable !== true) { 31 + console.log('FAIL: Function.prototype.toString.name descriptor flags should match builtin functions'); 32 + pass = false; 33 + } 34 + 35 + const lengthDesc = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'length'); 36 + if (!lengthDesc) { 37 + console.log('FAIL: Function.prototype.toString should expose a length descriptor'); 38 + pass = false; 39 + } 40 + 41 + if (!lengthDesc || lengthDesc.writable !== false || lengthDesc.enumerable !== false || lengthDesc.configurable !== true) { 42 + console.log('FAIL: Function.prototype.toString.length descriptor flags should match builtin functions'); 43 + pass = false; 44 + } 45 + 46 + const names = Object.getOwnPropertyNames(Function.prototype.toString); 47 + if (!names.includes('name') || !names.includes('length')) { 48 + console.log('FAIL: Object.getOwnPropertyNames should include builtin function metadata'); 49 + pass = false; 50 + } 51 + 52 + if (String.prototype.toLowerCase.name !== 'toLowerCase') { 53 + console.log('FAIL: shared native entrypoints should preserve the primary exposed name'); 54 + pass = false; 55 + } 56 + 57 + if (String.prototype.toLocaleLowerCase.name !== 'toLocaleLowerCase') { 58 + console.log('FAIL: shared native entrypoints should preserve alternate exposed names'); 59 + pass = false; 60 + } 61 + 62 + if (URLSearchParams.prototype[Symbol.iterator] !== URLSearchParams.prototype.entries) { 63 + console.log('FAIL: URLSearchParams @@iterator should alias entries'); 64 + pass = false; 65 + } 66 + 67 + if (URLSearchParams.prototype[Symbol.iterator].name !== 'entries') { 68 + console.log('FAIL: URLSearchParams @@iterator should keep the entries name'); 69 + pass = false; 70 + } 71 + 72 + if (Headers.prototype[Symbol.iterator] !== Headers.prototype.entries) { 73 + console.log('FAIL: Headers @@iterator should alias entries'); 74 + pass = false; 75 + } 76 + 77 + if (Headers.prototype[Symbol.iterator].name !== 'entries') { 78 + console.log('FAIL: Headers @@iterator should keep the entries name'); 79 + pass = false; 80 + } 81 + 82 + if (Map.prototype[Symbol.iterator] !== Map.prototype.entries) { 83 + console.log('FAIL: Map @@iterator should alias entries'); 84 + pass = false; 85 + } 86 + 87 + if (Map.prototype[Symbol.iterator].name !== 'entries') { 88 + console.log('FAIL: Map @@iterator should keep the entries name'); 89 + pass = false; 90 + } 91 + 92 + if (Set.prototype.keys !== Set.prototype.values || Set.prototype[Symbol.iterator] !== Set.prototype.values) { 93 + console.log('FAIL: Set iterator aliases should reuse values'); 94 + pass = false; 95 + } 96 + 97 + if (Set.prototype[Symbol.iterator].name !== 'values') { 98 + console.log('FAIL: Set @@iterator should keep the values name'); 99 + pass = false; 100 + } 101 + 102 + if (FormData.prototype[Symbol.iterator] !== FormData.prototype.entries) { 103 + console.log('FAIL: FormData @@iterator should alias entries'); 104 + pass = false; 105 + } 106 + 107 + if (EventEmitter.prototype.on !== EventEmitter.prototype.addListener) { 108 + console.log('FAIL: EventEmitter.addListener should alias on'); 109 + pass = false; 110 + } 111 + 112 + if (EventEmitter.prototype.off !== EventEmitter.prototype.removeListener) { 113 + console.log('FAIL: EventEmitter.removeListener should alias off'); 114 + pass = false; 115 + } 116 + 117 + if (process.on !== process.addListener || process.off !== process.removeListener) { 118 + console.log('FAIL: process event aliases should reuse the canonical methods'); 119 + pass = false; 120 + } 121 + 122 + if ( 123 + process.stdin.off !== process.stdin.removeListener || 124 + process.stdout.off !== process.stdout.removeListener || 125 + process.stderr.off !== process.stderr.removeListener 126 + ) { 127 + console.log('FAIL: stdio removeListener aliases should reuse the canonical methods'); 128 + pass = false; 129 + } 130 + 131 + if (Uint8Array.prototype[Symbol.iterator] !== Uint8Array.prototype.values) { 132 + console.log('FAIL: TypedArray @@iterator should alias values'); 133 + pass = false; 134 + } 135 + 136 + if (Uint8Array.prototype[Symbol.iterator].name !== 'values') { 137 + console.log('FAIL: TypedArray @@iterator should keep the values name'); 138 + pass = false; 139 + } 140 + 141 + const wrapped = (() => {}).bind(null); 142 + Object.defineProperty(wrapped, 'name', nameDesc); 143 + 144 + if (wrapped.name !== 'toString') { 145 + console.log('FAIL: builtin function name descriptors should round-trip through defineProperty'); 146 + pass = false; 147 + } 148 + 149 + if (pass) console.log('PASS');