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.

T_SYMBOL and NaN boxing changes

+95 -98
+6 -2
include/ant.h
··· 1 1 #pragma once 2 - 3 - #define PRIV_SYMBOL 0x80 4 2 #define PCRE2_CODE_UNIT_WIDTH 8 5 3 6 4 #include <stdbool.h> ··· 60 58 61 59 jsval_t js_getcurrentfunc(struct js *); 62 60 jsval_t js_get(struct js *, jsval_t, const char *); 61 + 62 + uint64_t js_sym_id(jsval_t sym); 63 + const char *js_sym_desc(struct js *js, jsval_t sym); 64 + 65 + jsval_t js_mksym_for(struct js *, const char *key); 66 + const char *js_sym_key(jsval_t sym); 63 67 64 68 jsval_t js_mkobj(struct js *); 65 69 jsval_t js_mkarr(struct js *);
+1 -1
meson.build
··· 74 74 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 75 75 76 76 version_conf = configuration_data() 77 - version_conf.set('ANT_VERSION', '0.2.1.15') 77 + version_conf.set('ANT_VERSION', '0.2.1.16') 78 78 version_conf.set('ANT_GIT_HASH', git_hash) 79 79 version_conf.set('ANT_BUILD_DATE', build_date) 80 80
+79 -38
src/ant.c
··· 424 424 enum { 425 425 T_OBJ, T_PROP, T_STR, T_UNDEF, T_NULL, T_NUM, 426 426 T_BOOL, T_FUNC, T_CODEREF, T_CFUNC, T_ERR, T_ARR, 427 - T_PROMISE, T_TYPEDARRAY, T_BIGINT, T_PROPREF 427 + T_PROMISE, T_TYPEDARRAY, T_BIGINT, T_PROPREF, T_SYMBOL, T_GENERATOR 428 428 }; 429 429 430 430 static const char *typestr_raw(uint8_t t) { 431 - if (t == PRIV_SYMBOL) return "symbol"; 432 - 433 431 const char *names[] = { 434 432 "object", "prop", "string", "undefined", "null", "number", 435 433 "boolean", "function", "coderef", "cfunc", "err", "array", 436 - "promise", "typedarray", "bigint", "propref" 434 + "promise", "typedarray", "bigint", "propref", "symbol", "generator" 437 435 }; 438 436 439 437 return (t < sizeof(names) / sizeof(names[0])) ? names[t] : "??"; ··· 441 439 442 440 static jsval_t tov(double d) { union { double d; jsval_t v; } u = {d}; return u.v; } 443 441 static double tod(jsval_t v) { union { jsval_t v; double d; } u = {v}; return u.d; } 444 - size_t vdata(jsval_t v) { return (size_t) (v & ~((jsval_t) 0x7fffUL << 48U)); } 442 + 443 + #define NANBOX_PREFIX 0x7FC0000000000000ULL 444 + #define NANBOX_PREFIX_CHK 0x3FEULL 445 + #define NANBOX_TYPE_SHIFT 48 446 + #define NANBOX_TYPE_MASK 0x1F 447 + #define NANBOX_DATA_MASK 0x0000FFFFFFFFFFFFULL 448 + 449 + static bool is_tagged(jsval_t v) { 450 + return (v >> 53) == NANBOX_PREFIX_CHK; 451 + } 452 + 453 + size_t vdata(jsval_t v) { 454 + return (size_t)(v & NANBOX_DATA_MASK); 455 + } 445 456 446 457 static jsoff_t coderefoff(jsval_t v) { return v & 0xffffffU; } 447 458 static jsoff_t codereflen(jsval_t v) { return (v >> 24U) & 0xffffffU; } ··· 454 465 static void saveoff(struct js *js, jsoff_t off, jsoff_t val) { memcpy(&js->mem[off], &val, sizeof(val)); } 455 466 static void saveval(struct js *js, jsoff_t off, jsval_t val) { memcpy(&js->mem[off], &val, sizeof(val)); } 456 467 457 - static bool is_nan(jsval_t v) { 458 - if ((v >> 52U) != 0x7feU) return false; 459 - // real doubles in 0x7FE range have large mantissa values 460 - // tagged values have small memory offsets, so upper data bits are 0 461 - return (v & 0xf00000000000UL) == 0; 462 - } 463 - 464 468 static const char *typestr(uint8_t t) { 465 469 if (t == T_CFUNC) return "function"; 466 470 if (t == T_ARR) return "object"; ··· 469 473 } 470 474 471 475 uint8_t vtype(jsval_t v) { 472 - return is_nan(v) ? ((v >> 48U) & 15U) : (uint8_t) T_NUM; 476 + return is_tagged(v) ? ((v >> NANBOX_TYPE_SHIFT) & NANBOX_TYPE_MASK) : (uint8_t)T_NUM; 473 477 } 474 478 475 479 static jsval_t mkval(uint8_t type, uint64_t data) { 476 - return ((jsval_t) 0x7fe0U << 48U) | ((jsval_t) (type) << 48) | (data & 0xffffffffffffUL); 480 + return NANBOX_PREFIX | ((jsval_t)(type & NANBOX_TYPE_MASK) << NANBOX_TYPE_SHIFT) | (data & NANBOX_DATA_MASK); 477 481 } 478 482 479 483 jsval_t js_obj_to_func(jsval_t obj) { ··· 3182 3186 } 3183 3187 3184 3188 jsval_t js_mksym(struct js *js, const char *desc) { 3185 - jsval_t sym_obj = mkobj(js, 0); 3186 3189 uint64_t id = ++js->symbol_counter; 3187 - setprop(js, sym_obj, js_mkstr(js, "__sym__", 7), mkval(T_BOOL, 1)); 3188 - setprop(js, sym_obj, js_mkstr(js, "__sym_id", 8), tov((double)id)); 3189 - if (desc) { 3190 - setprop(js, sym_obj, js_mkstr(js, "description", 11), js_mkstr(js, desc, strlen(desc))); 3191 - } else { 3192 - setprop(js, sym_obj, js_mkstr(js, "description", 11), mkval(T_UNDEF, 0)); 3190 + jsoff_t desc_off = 0; 3191 + if (desc && *desc) { 3192 + jsval_t desc_str = js_mkstr(js, desc, strlen(desc)); 3193 + desc_off = (jsoff_t)vdata(desc_str); 3193 3194 } 3194 - return sym_obj; 3195 + uint64_t payload = ((id & 0xFFFFFFULL) << 24) | (desc_off & 0xFFFFFFULL); 3196 + return mkval(T_SYMBOL, payload); 3195 3197 } 3196 3198 3197 3199 static bool is_symbol(struct js *js, jsval_t v) { 3198 - if (vtype(v) != T_OBJ) return false; 3199 - jsoff_t off = lkp(js, v, "__sym__", 7); 3200 - return off != 0; 3200 + (void)js; 3201 + return vtype(v) == T_SYMBOL; 3202 + } 3203 + 3204 + static uint64_t sym_get_id(jsval_t v) { 3205 + return (vdata(v) >> 24) & 0xFFFFFFULL; 3206 + } 3207 + 3208 + static jsoff_t sym_get_desc_off(jsval_t v) { 3209 + return vdata(v) & 0xFFFFFFULL; 3210 + } 3211 + 3212 + static const char *sym_get_desc(struct js *js, jsval_t v) { 3213 + jsoff_t off = sym_get_desc_off(v); 3214 + if (off == 0) return NULL; 3215 + return (const char *)&js->mem[off + sizeof(jsoff_t)]; 3216 + } 3217 + 3218 + uint64_t js_sym_id(jsval_t sym) { 3219 + return sym_get_id(sym); 3220 + } 3221 + 3222 + jsval_t js_mksym_for(struct js *js, const char *key) { 3223 + (void)js; 3224 + const char *interned = intern_string(key, strlen(key)); 3225 + uint64_t id = (uint64_t)(uintptr_t)interned; 3226 + return mkval(T_SYMBOL, id | (1ULL << 47)); 3227 + } 3228 + 3229 + const char *js_sym_key(jsval_t sym) { 3230 + if (vtype(sym) != T_SYMBOL) return NULL; 3231 + uint64_t data = vdata(sym); 3232 + if (!(data & (1ULL << 47))) return NULL; 3233 + return (const char *)(uintptr_t)(data & ~(1ULL << 47)); 3234 + } 3235 + 3236 + const char *js_sym_desc(struct js *js, jsval_t sym) { 3237 + return sym_get_desc(js, sym); 3201 3238 } 3202 3239 3203 3240 static inline jsoff_t esize(jsoff_t w) { ··· 4718 4755 jsoff_t off = vstr(js, key_val, &slen); 4719 4756 keystr = (char *) &js->mem[off]; 4720 4757 keylen = slen; 4721 - } else if (vtype(key_val) == T_OBJ && is_symbol(js, key_val)) { 4722 - jsval_t sym_id = resolveprop(js, mkval(T_PROP, lkp(js, key_val, "__sym_id", 8))); 4723 - snprintf(keybuf, sizeof(keybuf), "__sym_%.0f__", tod(sym_id)); 4758 + } else if (vtype(key_val) == T_SYMBOL) { 4759 + snprintf(keybuf, sizeof(keybuf), "__sym_%llu__", (unsigned long long)sym_get_id(key_val)); 4724 4760 keystr = keybuf; 4725 4761 keylen = strlen(keybuf); 4726 4762 } else { ··· 4879 4915 return js_mkundef(); 4880 4916 } 4881 4917 4918 + if (t == T_SYMBOL) { 4919 + if (streq(ptr, plen, "description", 11)) { 4920 + const char *desc = sym_get_desc(js, l); 4921 + if (desc) return js_mkstr(js, desc, strlen(desc)); 4922 + return js_mkundef(); 4923 + } 4924 + return js_mkundef(); 4925 + } 4926 + 4882 4927 if (t != T_OBJ && t != T_ARR) { 4883 4928 char errbuf[256]; 4884 4929 jsoff_t saved_toff = js->toff; ··· 6060 6105 6061 6106 switch (op) { 6062 6107 case TOK_TYPEOF: { 6063 - const char *ts = (vtype(r) == T_OBJ && is_symbol(js, r)) ? "symbol" : typestr(vtype(r)); 6108 + const char *ts = typestr(vtype(r)); 6064 6109 return js_mkstr(js, ts, strlen(ts)); 6065 6110 } 6066 6111 case TOK_VOID: return js_mkundef(); ··· 7058 7103 jsval_t resolved_key = resolveprop(js, key_expr); 7059 7104 if (vtype(resolved_key) == T_STR) { 7060 7105 key = resolved_key; 7061 - } else if (vtype(resolved_key) == T_OBJ && is_symbol(js, resolved_key)) { 7106 + } else if (vtype(resolved_key) == T_SYMBOL) { 7062 7107 char buf[64]; 7063 - jsoff_t sym_id_off = lkp(js, resolved_key, "__sym_id", 8); 7064 - if (sym_id_off) { 7065 - jsval_t sym_id = loadval(js, sym_id_off + sizeof(jsoff_t) * 2); 7066 - snprintf(buf, sizeof(buf), "__sym_%.0f__", tod(sym_id)); 7067 - } else { 7068 - snprintf(buf, sizeof(buf), "__sym_0__"); 7069 - } 7108 + snprintf(buf, sizeof(buf), "__sym_%llu__", (unsigned long long)sym_get_id(resolved_key)); 7070 7109 key = js_mkstr(js, buf, strlen(buf)); 7071 7110 } else { 7072 7111 char buf[64]; ··· 20965 21004 case T_NUM: return JS_NUM; 20966 21005 case T_ERR: return JS_ERR; 20967 21006 case T_PROMISE: return JS_PROMISE; 21007 + case T_SYMBOL: return JS_SYMBOL; 20968 21008 20969 21009 case T_OBJ: 20970 21010 case T_ARR: return JS_OBJ; ··· 20975 21015 } 20976 21016 20977 21017 int js_type_ex(struct js *js, jsval_t val) { 20978 - if (vtype(val) == T_OBJ && is_symbol(js, val)) return JS_SYMBOL; 21018 + (void)js; 21019 + if (vtype(val) == T_SYMBOL) return JS_SYMBOL; 20979 21020 return js_type(val); 20980 21021 } 20981 21022
+9 -57
src/modules/symbol.c
··· 6 6 #include "runtime.h" 7 7 #include "modules/symbol.h" 8 8 9 - #define MAX_REGISTRY 256 10 - static struct { 11 - char *key; 12 - jsval_t symbol; 13 - } g_symbol_registry[MAX_REGISTRY]; 14 - static int g_registry_count = 0; 15 - 16 9 static jsval_t g_iterator_sym = 0; 17 10 static jsval_t g_toStringTag_sym = 0; 18 11 static jsval_t g_hasInstance_sym = 0; ··· 40 33 char *key = js_getstr(js, args[0], NULL); 41 34 if (!key) return js_mkerr(js, "Invalid key"); 42 35 43 - for (int i = 0; i < g_registry_count; i++) { 44 - if (g_symbol_registry[i].key && strcmp(g_symbol_registry[i].key, key) == 0) { 45 - return g_symbol_registry[i].symbol; 46 - } 47 - } 48 - 49 - if (g_registry_count >= MAX_REGISTRY) { 50 - return js_mkerr(js, "Symbol registry full"); 51 - } 52 - 53 - jsval_t sym = js_mksym(js, key); 54 - g_symbol_registry[g_registry_count].key = strdup(key); 55 - g_symbol_registry[g_registry_count].symbol = sym; 56 - 57 - jsval_t sym_obj = js_mkobj(js); 58 - js_set(js, sym_obj, "__sym_id", js_get(js, sym, "__sym_id")); 59 - js_set(js, sym_obj, "description", js_get(js, sym, "description")); 60 - js_set(js, sym_obj, "__registry_key", js_mkstr(js, key, strlen(key))); 61 - 62 - g_symbol_registry[g_registry_count].symbol = sym; 63 - g_registry_count++; 64 - 65 - return sym; 66 - } 67 - 68 - static bool is_symbol_val(struct js *js, jsval_t v) { 69 - if (js_type(v) != JS_OBJ) return false; 70 - jsval_t marker = js_get(js, v, "__sym__"); 71 - return js_type(marker) == JS_TRUE; 36 + return js_mksym_for(js, key); 72 37 } 73 38 74 39 static jsval_t builtin_Symbol_keyFor(struct js *js, jsval_t *args, int nargs) { 75 - if (nargs < 1 || !is_symbol_val(js, args[0])) { 40 + if (nargs < 1 || js_type(args[0]) != JS_SYMBOL) { 76 41 return js_mkundef(); 77 42 } 78 43 79 - jsval_t sym = args[0]; 80 - jsval_t sym_id = js_get(js, sym, "__sym_id"); 81 - 82 - for (int i = 0; i < g_registry_count; i++) { 83 - jsval_t reg_id = js_get(js, g_symbol_registry[i].symbol, "__sym_id"); 84 - if (js_type(sym_id) == JS_NUM && js_type(reg_id) == JS_NUM && 85 - js_getnum(sym_id) == js_getnum(reg_id)) { 86 - return js_mkstr(js, g_symbol_registry[i].key, strlen(g_symbol_registry[i].key)); 87 - } 88 - } 44 + const char *key = js_sym_key(args[0]); 45 + if (!key) return js_mkundef(); 89 46 90 - return js_mkundef(); 47 + return js_mkstr(js, key, strlen(key)); 91 48 } 92 49 93 50 static jsval_t iterator_next(struct js *js, jsval_t *args, int nargs) { ··· 196 153 g_toStringTag_sym = js_mksym(js, "Symbol.toStringTag"); 197 154 g_hasInstance_sym = js_mksym(js, "Symbol.hasInstance"); 198 155 199 - jsval_t iter_sym_id = js_get(js, g_iterator_sym, "__sym_id"); 200 - snprintf(g_iter_sym_key, sizeof(g_iter_sym_key), "__sym_%.0f__", js_getnum(iter_sym_id)); 201 - 202 - jsval_t tag_sym_id = js_get(js, g_toStringTag_sym, "__sym_id"); 203 - snprintf(g_toStringTag_sym_key, sizeof(g_toStringTag_sym_key), "__sym_%.0f__", js_getnum(tag_sym_id)); 156 + snprintf(g_iter_sym_key, sizeof(g_iter_sym_key), "__sym_%llu__", (unsigned long long)js_sym_id(g_iterator_sym)); 157 + snprintf(g_toStringTag_sym_key, sizeof(g_toStringTag_sym_key), "__sym_%llu__", (unsigned long long)js_sym_id(g_toStringTag_sym)); 204 158 205 159 jsval_t symbol_ctor = js_mkobj(js); 206 160 js_set(js, symbol_ctor, "__native_func", js_mkfun(builtin_Symbol)); ··· 211 165 js_set(js, symbol_ctor, "toStringTag", g_toStringTag_sym); 212 166 js_set(js, symbol_ctor, "hasInstance", g_hasInstance_sym); 213 167 214 - jsval_t func_symbol = symbol_ctor; 215 - *(uint64_t*)&func_symbol = (func_symbol & ~((uint64_t)0xF << 48)) | ((uint64_t)0x7 << 48); 216 - 168 + jsval_t func_symbol = js_obj_to_func(symbol_ctor); 217 169 js_set(js, js_glob(js), "Symbol", func_symbol); 218 170 171 + // set internal types before module ready 219 172 jsval_t array_ctor = js_get(js, js_glob(js), "Array"); 220 173 jsval_t array_proto = js_get(js, array_ctor, "prototype"); 221 174 js_set(js, array_proto, g_iter_sym_key, js_mkfun(array_iterator)); ··· 224 177 jsval_t string_proto = js_get(js, string_ctor, "prototype"); 225 178 js_set(js, string_proto, g_iter_sym_key, js_mkfun(string_iterator)); 226 179 227 - // set internal types before module ready 228 180 jsval_t map_ctor = js_get(js, js_glob(js), "Map"); 229 181 jsval_t map_proto = js_get(js, map_ctor, "prototype"); 230 182 if (js_type(map_proto) == JS_OBJ) {