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 slot types and functions for internal slots

+742 -596
+15 -1
include/ant.h
··· 5 5 #include <stddef.h> 6 6 #include <stdint.h> 7 7 #include <stdio.h> 8 + #include <config.h> 9 + 10 + #define STR_PROTO "__proto__" 11 + #define STR_PROTO_LEN 9 8 12 9 13 struct js; 14 + 15 + typedef uint32_t jsoff_t; 10 16 typedef uint64_t jsval_t; 11 17 12 18 enum { ··· 142 148 void js_set_setter_desc(struct js *js, jsval_t obj, const char *key, size_t klen, jsval_t setter, int flags); 143 149 void js_set_accessor_desc(struct js *js, jsval_t obj, const char *key, size_t klen, jsval_t getter, jsval_t setter, int flags); 144 150 145 - void js_print_stack_trace(FILE *stream); 151 + void js_print_stack_trace(FILE *stream); 152 + 153 + jsval_t js_get_slot(struct js *js, jsval_t obj, internal_slot_t slot); 154 + void js_set_slot(struct js *js, jsval_t obj, internal_slot_t slot, jsval_t value); 155 + 156 + 157 + bool js_is_slot_prop(jsoff_t header); 158 + jsoff_t js_next_prop(jsoff_t header); 159 + jsoff_t js_loadoff(struct js *js, jsoff_t off);
+12
include/config.h
··· 23 23 typedef enum { 24 24 SLOT_NONE = 0, 25 25 SLOT_PID, 26 + SLOT_ASYNC, 27 + SLOT_WITH, 28 + SLOT_SCOPE, 29 + SLOT_THIS, 30 + SLOT_BOUND_THIS, 31 + SLOT_BOUND_ARGS, 32 + SLOT_STRICT, 33 + SLOT_FIELD_COUNT, 34 + SLOT_CODE, 35 + SLOT_CFUNC, 36 + SLOT_CORO, 37 + SLOT_PROTO, 26 38 SLOT_MAX = 255 27 39 } internal_slot_t; 28 40
+12
include/config.h.in
··· 15 15 typedef enum { 16 16 SLOT_NONE = 0, 17 17 SLOT_PID, 18 + SLOT_ASYNC, 19 + SLOT_WITH, 20 + SLOT_SCOPE, 21 + SLOT_THIS, 22 + SLOT_BOUND_THIS, 23 + SLOT_BOUND_ARGS, 24 + SLOT_FIELD_COUNT, 25 + SLOT_STRICT, 26 + SLOT_CODE, 27 + SLOT_CFUNC, 28 + SLOT_CORO, 29 + SLOT_PROTO, 18 30 SLOT_MAX = 255 19 31 } internal_slot_t; 20 32
+1 -1
meson.build
··· 79 79 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 80 80 81 81 version_conf = configuration_data() 82 - version_conf.set('ANT_VERSION', '0.2.2.34') 82 + version_conf.set('ANT_VERSION', '0.2.2.35') 83 83 version_conf.set('ANT_GIT_HASH', git_hash) 84 84 version_conf.set('ANT_BUILD_DATE', build_date) 85 85
+695 -587
src/ant.c
··· 37 37 #define CORO_MALLOC(size) calloc(1, size) 38 38 #define CORO_FREE(ptr) free(ptr) 39 39 40 + /* ========== PERFORMANCE INSTRUMENTATION ========== */ 41 + #define PERF_INSTRUMENTATION 1 42 + 43 + #if PERF_INSTRUMENTATION 44 + #include <mach/mach_time.h> 45 + 46 + static uint64_t perf_call_count = 0; 47 + static uint64_t perf_phase4_ns = 0; 48 + static uint64_t perf_phase4_sub1_ns = 0; // Parameter binding loop 49 + static uint64_t perf_phase4_sub2_ns = 0; // Rest parameter handling 50 + static uint64_t perf_phase4_sub3_ns = 0; // code_uses_arguments check 51 + static uint64_t perf_phase4_sub4_ns = 0; // setup_arguments 52 + static uint64_t perf_phase4_sub5_ns = 0; // NFE name binding 53 + static uint64_t perf_phase4_sub6_ns = 0; // Strict mode lookup + this handling 54 + static uint64_t perf_sub5_vstr_ns = 0; // vstr inside sub5 55 + static uint64_t perf_sub5_mkprop_ns = 0; // mkprop inside sub5 56 + static uint64_t perf_sub5_count = 0; // Times sub5 actually runs 57 + static uint64_t perf_mkprop_intern_ns = 0; // intern_string inside mkprop 58 + static uint64_t perf_mkprop_setkoff_ns = 0; // set_koff_intern inside mkprop 59 + static uint64_t perf_mkprop_mkentity_ns = 0; // mkentity inside mkprop 60 + static uint64_t perf_mkprop_setup_ns = 0; // setup (memcpy) inside mkprop 61 + static uint64_t perf_mkprop_count = 0; 62 + static uint64_t perf_lkp_calls = 0; 63 + static uint64_t perf_lkp_cache_hits = 0; 64 + static uint64_t perf_lkp_not_found = 0; 65 + static uint64_t perf_lkp_found_no_cache = 0; /* Found but wasn't in cache */ 66 + static uint64_t perf_lkp_trace_count = 0; 67 + #define PERF_LKP_TRACE 1 /* Set to 1 to trace lookups */ 68 + static uint64_t perf_report_interval = 100000; 69 + static mach_timebase_info_data_t perf_timebase = {0}; 70 + 71 + static inline uint64_t perf_now_ns(void) { 72 + if (perf_timebase.denom == 0) mach_timebase_info(&perf_timebase); 73 + return mach_absolute_time() * perf_timebase.numer / perf_timebase.denom; 74 + } 75 + 76 + static void perf_report(size_t heap_size) { 77 + if (perf_call_count == 0) return; 78 + fprintf(stderr, "\n[PERF] After %llu calls, heap=%zu KB\n", perf_call_count, heap_size / 1024); 79 + fprintf(stderr, "[PERF] phase4 total: %.1f ns/call\n", (double)perf_phase4_ns / perf_call_count); 80 + fprintf(stderr, "[PERF] sub1 (param bind): %.1f ns\n", (double)perf_phase4_sub1_ns / perf_call_count); 81 + fprintf(stderr, "[PERF] sub2 (rest params): %.1f ns\n", (double)perf_phase4_sub2_ns / perf_call_count); 82 + fprintf(stderr, "[PERF] sub3 (uses_arguments): %.1f ns\n", (double)perf_phase4_sub3_ns / perf_call_count); 83 + fprintf(stderr, "[PERF] sub4 (setup_args): %.1f ns\n", (double)perf_phase4_sub4_ns / perf_call_count); 84 + fprintf(stderr, "[PERF] sub5 (NFE bind): %.1f ns (runs=%llu, %.1f%%)\n", 85 + (double)perf_phase4_sub5_ns / perf_call_count, 86 + perf_sub5_count, 100.0 * perf_sub5_count / perf_call_count); 87 + if (perf_sub5_count > 0) { 88 + fprintf(stderr, "[PERF] sub5.vstr: %.1f ns/run\n", (double)perf_sub5_vstr_ns / perf_sub5_count); 89 + fprintf(stderr, "[PERF] sub5.mkprop: %.1f ns/run\n", (double)perf_sub5_mkprop_ns / perf_sub5_count); 90 + } 91 + fprintf(stderr, "[PERF] sub6 (strict+this): %.1f ns\n", (double)perf_phase4_sub6_ns / perf_call_count); 92 + if (perf_mkprop_count > 0) { 93 + fprintf(stderr, "[PERF] mkprop breakdown (%llu calls):\n", perf_mkprop_count); 94 + fprintf(stderr, "[PERF] setup: %.1f ns\n", (double)perf_mkprop_setup_ns / perf_mkprop_count); 95 + fprintf(stderr, "[PERF] intern: %.1f ns\n", (double)perf_mkprop_intern_ns / perf_mkprop_count); 96 + fprintf(stderr, "[PERF] setkoff: %.1f ns\n", (double)perf_mkprop_setkoff_ns / perf_mkprop_count); 97 + fprintf(stderr, "[PERF] mkentity: %.1f ns\n", (double)perf_mkprop_mkentity_ns / perf_mkprop_count); 98 + } 99 + if (perf_lkp_calls > 0) { 100 + fprintf(stderr, "[PERF] lkp_interned: %llu calls, %.1f%% cache hits, %.1f%% found (no cache), %.1f%% not found\n", 101 + perf_lkp_calls, 102 + 100.0 * perf_lkp_cache_hits / perf_lkp_calls, 103 + 100.0 * perf_lkp_found_no_cache / perf_lkp_calls, 104 + 100.0 * perf_lkp_not_found / perf_lkp_calls); 105 + fprintf(stderr, "[PERF] per function call: %.1f lookups\n", (double)perf_lkp_calls / perf_call_count); 106 + } 107 + } 108 + 109 + #define PERF_START(var) uint64_t var = perf_now_ns() 110 + #define PERF_END(var, accum) (accum) += (perf_now_ns() - (var)) 111 + #define PERF_CALL_INC() (++perf_call_count) 112 + #define PERF_SHOULD_REPORT() ((perf_call_count % perf_report_interval) == 0) 113 + #else 114 + #define PERF_START(var) (void)0 115 + #define PERF_END(var, accum) (void)0 116 + #define PERF_CALL_INC() (void)0 117 + #define PERF_SHOULD_REPORT() (false) 118 + #endif 119 + /* ========== END PERFORMANCE INSTRUMENTATION ========== */ 120 + 40 121 _Static_assert(sizeof(double) == 8, "NaN-boxing requires 64-bit IEEE 754 doubles"); 41 122 _Static_assert(sizeof(uint64_t) == 8, "NaN-boxing requires 64-bit integers"); 42 123 _Static_assert(sizeof(double) == sizeof(uint64_t), "double and uint64_t must have same size"); ··· 49 130 #error "NaN-boxing requires IEEE 754 binary64 doubles" 50 131 #endif 51 132 52 - typedef uint32_t jsoff_t; 53 - 54 133 typedef struct { 55 134 jsval_t *stack; 56 135 int depth; ··· 206 285 struct interned_string *next; 207 286 } interned_string_t; 208 287 209 - typedef struct koff_intern { 210 - jsoff_t koff; 211 - const char *interned; 212 - struct koff_intern *next; 213 - } koff_intern_t; 214 - 215 288 #define INTERN_BUCKETS 16384 216 289 static interned_string_t *intern_buckets[INTERN_BUCKETS]; 217 290 218 - #define KOFF_BUCKETS 16384 219 - static koff_intern_t *koff_buckets[KOFF_BUCKETS]; 220 - 221 - static const char *INTERN_PROTO = NULL; 222 291 static const char *INTERN_LENGTH = NULL; 223 292 static const char *INTERN_PROTOTYPE = NULL; 224 293 static const char *INTERN_CONSTRUCTOR = NULL; ··· 227 296 static const char *INTERN_VALUE = NULL; 228 297 static const char *INTERN_GET = NULL; 229 298 static const char *INTERN_SET = NULL; 230 - static const char *INTERN_CODE = NULL; 231 - static const char *INTERN_SCOPE = NULL; 232 - static const char *INTERN_THIS = NULL; 233 - static const char *INTERN_NATIVE_FUNC = NULL; 234 - static const char *INTERN_ASYNC = NULL; 235 - static const char *INTERN_BOUND_THIS = NULL; 236 - static const char *INTERN_BOUND_ARGS = NULL; 237 299 static const char *INTERN_TARGET_FUNC = NULL; 238 300 static const char *INTERN_ARGUMENTS = NULL; 239 301 static const char *INTERN_CALLEE = NULL; ··· 428 490 bool had_newline; // true if newline was crossed before current token 429 491 jsval_t thrown_value; // stores the actual thrown value for catch blocks 430 492 bool is_hoisting; // true during function declaration hoisting pass 431 - uint64_t symbol_counter; // counter for generating unique symbol IDs 493 + uint64_t sym_counter; // counter for generating unique symbol IDs 432 494 }; 433 495 434 496 enum { ··· 501 563 } 502 564 503 565 #define PROPREF_STACK_FLAG 0x800000000000ULL 504 - #define PROPREF_INDEX_MASK 0x7FFFFFFFFFFFULL 566 + #define PROPREF_PRIM_FLAG 0x400000000000ULL 567 + #define PROPREF_INDEX_MASK 0x3FFFFFFFFFFFULL 505 568 #define PROPREF_OFF_MASK 0xFFFFFFU 506 569 #define PROPREF_PAYLOAD 0xFFFFFFULL 507 570 #define PROPREF_KEY_SHIFT 24U 508 571 572 + typedef struct { 573 + jsval_t prim_val; 574 + jsoff_t key_off; 575 + } prim_propref_data_t; 576 + 577 + static UT_icd prim_propref_icd = { sizeof(prim_propref_data_t), NULL, NULL, NULL }; 578 + static UT_array *prim_propref_stack = NULL; 579 + 509 580 static jsoff_t coderefoff(jsval_t v) { return v & PROPREF_OFF_MASK; } 510 581 static jsoff_t codereflen(jsval_t v) { return (v >> 24U) & PROPREF_OFF_MASK; } 511 582 ··· 597 668 return mkval(T_PROPREF, PROPREF_STACK_FLAG | (uint64_t)idx); 598 669 } 599 670 671 + static jsval_t mkprim_propref(jsval_t prim_val, jsoff_t key_off) { 672 + if (!prim_propref_stack) utarray_new(prim_propref_stack, &prim_propref_icd); 673 + if (utarray_len(prim_propref_stack) > 256) utarray_clear(prim_propref_stack); 674 + 675 + prim_propref_data_t entry = { prim_val, key_off }; 676 + utarray_push_back(prim_propref_stack, &entry); 677 + int idx = (int)utarray_len(prim_propref_stack) - 1; 678 + 679 + return mkval(T_PROPREF, PROPREF_PRIM_FLAG | (uint64_t)idx); 680 + } 681 + 682 + static inline bool is_prim_propref(jsval_t v) { 683 + if (vtype(v) != T_PROPREF) return false; 684 + uint64_t data = v & NANBOX_DATA_MASK; 685 + return (data & PROPREF_PRIM_FLAG) != 0; 686 + } 687 + 688 + static inline prim_propref_data_t *prim_propref_get(jsval_t v) { 689 + uint64_t data = v & NANBOX_DATA_MASK; 690 + if (!(data & PROPREF_PRIM_FLAG)) return NULL; 691 + 692 + int idx = (int)(data & PROPREF_INDEX_MASK); 693 + if (!prim_propref_stack || idx < 0 || idx >= (int)utarray_len(prim_propref_stack)) return NULL; 694 + 695 + return (prim_propref_data_t *)utarray_eltptr(prim_propref_stack, (unsigned)idx); 696 + } 697 + 600 698 static inline bool is_err(jsval_t v) { 601 699 return vtype(v) == T_ERR; 602 700 } ··· 748 846 static jsval_t resolveprop(struct js *js, jsval_t v); 749 847 static jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len); 750 848 static jsoff_t lkp_interned(struct js *js, jsval_t obj, const char *search_intern, size_t len); 751 - static inline const char *get_koff_intern(jsoff_t koff); 849 + static const char *intern_string(const char *str, size_t len); 850 + static jsval_t get_slot(struct js *js, jsval_t obj, internal_slot_t slot); 851 + static void set_slot(struct js *js, jsval_t obj, internal_slot_t slot, jsval_t value); 852 + static inline bool is_slot_prop(jsoff_t header); 853 + static inline jsoff_t next_prop(jsoff_t header); 752 854 753 855 static jsval_t js_import_stmt(struct js *js); 754 856 static jsval_t js_export_stmt(struct js *js); ··· 1143 1245 1144 1246 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1145 1247 while (next < js->brk && next != 0) { 1146 - jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1147 - jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1148 - scan_refs(js, val); 1149 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1248 + jsoff_t header = loadoff(js, next); 1249 + if (!is_slot_prop(header)) { 1250 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1251 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1252 + scan_refs(js, val); 1253 + } 1254 + next = next_prop(header); 1150 1255 } 1151 1256 1152 - jsoff_t proto_off = lkp_interned(js, obj, INTERN_PROTO, 9); 1153 - if (proto_off != 0) { 1154 - jsval_t proto_val = resolveprop(js, mkval(T_PROP, proto_off)); 1155 - if (vtype(proto_val) == T_OBJ) scan_refs(js, proto_val); 1156 - } 1257 + jsval_t proto_val = get_slot(js, obj, SLOT_PROTO); 1258 + if (vtype(proto_val) == T_OBJ) scan_refs(js, proto_val); 1157 1259 1158 1260 stringify_depth--; 1159 1261 } ··· 1169 1271 1170 1272 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1171 1273 while (next < js->brk && next != 0) { 1172 - jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1173 - jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1174 - scan_refs(js, val); 1175 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1274 + jsoff_t header = loadoff(js, next); 1275 + if (!is_slot_prop(header)) { 1276 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1277 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1278 + scan_refs(js, val); 1279 + } 1280 + next = next_prop(header); 1176 1281 } 1177 1282 1178 1283 stringify_depth--; ··· 1191 1296 1192 1297 jsoff_t next = loadoff(js, (jsoff_t) vdata(func_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1193 1298 while (next < js->brk && next != 0) { 1194 - jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1195 - jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1196 - scan_refs(js, val); 1197 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1299 + jsoff_t header = loadoff(js, next); 1300 + if (!is_slot_prop(header)) { 1301 + jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1302 + jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 1303 + scan_refs(js, val); 1304 + } 1305 + next = next_prop(header); 1198 1306 } 1199 1307 1200 1308 stringify_depth--; ··· 1442 1550 jsoff_t proto_next = loadoff(js, (jsoff_t) vdata(proto_val)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1443 1551 1444 1552 while (proto_next < js->brk && proto_next != 0) { 1553 + jsoff_t pheader = loadoff(js, proto_next); 1554 + if (is_slot_prop(pheader)) { proto_next = next_prop(pheader); continue; } 1555 + 1445 1556 jsoff_t pkoff = loadoff(js, proto_next + (jsoff_t) sizeof(proto_next)); 1446 1557 jsoff_t pklen = offtolen(loadoff(js, pkoff)); 1447 1558 const char *pkstr = (const char *) &js->mem[pkoff + sizeof(jsoff_t)]; 1448 1559 1449 1560 const char *tag_key = get_toStringTag_sym_key(); 1450 1561 size_t tag_key_len = strlen(tag_key); 1451 - if (!streq(pkstr, pklen, "__proto__", 9) && !streq(pkstr, pklen, "constructor", 11) && !streq(pkstr, pklen, tag_key, tag_key_len)) { 1562 + if (!streq(pkstr, pklen, STR_PROTO, STR_PROTO_LEN) && !streq(pkstr, pklen, "constructor", 11) && !streq(pkstr, pklen, tag_key, tag_key_len)) { 1452 1563 has_proto_props = true; 1453 1564 break; 1454 1565 } 1455 - proto_next = loadoff(js, proto_next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1566 + proto_next = next_prop(pheader); 1456 1567 } 1457 1568 1458 1569 if (!*first) n += cpy(buf + n, len - n, ",\n", 2); ··· 1466 1577 bool proto_first = true; 1467 1578 proto_next = loadoff(js, (jsoff_t) vdata(proto_val)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1468 1579 while (proto_next < js->brk && proto_next != 0) { 1580 + jsoff_t pheader = loadoff(js, proto_next); 1581 + if (is_slot_prop(pheader)) { proto_next = next_prop(pheader); continue; } 1582 + 1469 1583 jsoff_t pkoff = loadoff(js, proto_next + (jsoff_t) sizeof(proto_next)); 1470 1584 jsval_t pval = loadval(js, proto_next + (jsoff_t) (sizeof(proto_next) + sizeof(pkoff))); 1471 1585 ··· 1474 1588 1475 1589 const char *tag_key2 = get_toStringTag_sym_key(); 1476 1590 size_t tag_key_len2 = strlen(tag_key2); 1477 - if (!streq(pkstr, pklen, "__proto__", 9) && !streq(pkstr, pklen, "constructor", 11) && !streq(pkstr, pklen, tag_key2, tag_key_len2)) { 1591 + if (!streq(pkstr, pklen, STR_PROTO, STR_PROTO_LEN) && !streq(pkstr, pklen, "constructor", 11) && !streq(pkstr, pklen, tag_key2, tag_key_len2)) { 1478 1592 if (!proto_first) n += cpy(buf + n, len - n, ",\n", 2); 1479 1593 proto_first = false; 1480 1594 n += add_indent(buf + n, len - n, stringify_indent); ··· 1482 1596 n += cpy(buf + n, len - n, ": ", 2); 1483 1597 n += tostr(js, pval, buf + n, len - n); 1484 1598 } 1485 - proto_next = loadoff(js, proto_next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1599 + proto_next = next_prop(pheader); 1486 1600 } 1487 1601 1488 1602 stringify_indent--; ··· 1628 1742 bool first = true; 1629 1743 1630 1744 while (next < js->brk && next != 0) { 1745 + jsoff_t header = loadoff(js, next); 1746 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 1747 + 1631 1748 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1632 1749 jsoff_t klen = offtolen(loadoff(js, koff)); 1633 1750 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 1634 1751 1635 1752 bool is_desc = (klen > 7 && key[0] == '_' && key[1] == '_' && key[2] == 'd' && key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_'); 1636 1753 const char *tag_sym_key = get_toStringTag_sym_key(); 1637 - bool should_hide = streq(key, klen, "__proto__", 9) || streq(key, klen, tag_sym_key, strlen(tag_sym_key)) || is_desc; 1754 + bool should_hide = streq(key, klen, STR_PROTO, STR_PROTO_LEN) || streq(key, klen, tag_sym_key, strlen(tag_sym_key)) || is_desc; 1638 1755 1639 1756 if (!should_hide) { 1640 1757 jsoff_t obj_off = (jsoff_t)vdata(obj); ··· 1674 1791 n += tostr(js, val, buf + n, len - n); 1675 1792 } 1676 1793 } 1677 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1794 + next = next_prop(header); 1678 1795 } 1679 1796 1680 1797 next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1681 1798 while (next < js->brk && next != 0) { 1799 + jsoff_t header = loadoff(js, next); 1800 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 1801 + 1682 1802 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1683 1803 jsoff_t klen = offtolen(loadoff(js, koff)); 1684 1804 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 1730 1850 } 1731 1851 } 1732 1852 } 1733 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1853 + next = next_prop(header); 1734 1854 } 1735 1855 1736 1856 stringify_indent--; ··· 1830 1950 1831 1951 if (key[0] == '_' && key[1] == '_') return true; 1832 1952 1833 - const char *interned = get_koff_intern(koff); 1834 - if (interned) { 1835 - if (interned == INTERN_PROTOTYPE || interned == INTERN_CONSTRUCTOR) return true; 1836 - if (interned == get_toStringTag_sym_key()) return true; 1837 - } 1953 + const char *interned = intern_string(key, klen); 1954 + if (interned == INTERN_PROTOTYPE || interned == INTERN_CONSTRUCTOR) return true; 1955 + if (interned == get_toStringTag_sym_key()) return true; 1838 1956 1839 1957 return false; 1840 1958 } ··· 1850 1968 1851 1969 jsoff_t next = loadoff(js, (jsoff_t) vdata(func_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1852 1970 while (next < js->brk && next != 0) { 1971 + jsoff_t header = loadoff(js, next); 1972 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 1973 + 1853 1974 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 1854 1975 jsoff_t klen = offtolen(loadoff(js, koff)); 1855 1976 const char *kstr = (const char *) &js->mem[koff + sizeof(jsoff_t)]; ··· 1863 1984 n += cpy(buf + n, len - n, ": ", 2); 1864 1985 n += tostr(js, val, buf + n, len - n); 1865 1986 } 1866 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 1987 + next = next_prop(header); 1867 1988 } 1868 1989 1869 1990 jsoff_t proto_off = lkp_interned(js, func_obj, INTERN_PROTOTYPE, 9); ··· 1882 2003 1883 2004 static size_t strfunc(struct js *js, jsval_t value, char *buf, size_t len) { 1884 2005 jsval_t func_obj = mkval(T_OBJ, vdata(value)); 1885 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 2006 + jsval_t code_slot = get_slot(js, func_obj, SLOT_CODE); 1886 2007 1887 2008 jsoff_t name_off = lkp(js, func_obj, "name", 4); 1888 2009 const char *name = NULL; ··· 1896 2017 } 1897 2018 } 1898 2019 1899 - if (code_off == 0) { 1900 - jsoff_t native_off = lkp_interned(js, func_obj, INTERN_NATIVE_FUNC, 13); 1901 - if (native_off != 0) { 1902 - jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 1903 - if (vtype(native_val) == T_CFUNC) return strfunc_ctor(js, func_obj, buf, len); 1904 - } 2020 + if (vtype(code_slot) != T_STR) { 2021 + jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 2022 + if (vtype(cfunc_slot) == T_CFUNC) return strfunc_ctor(js, func_obj, buf, len); 1905 2023 if (name && name_len > 0) { 1906 2024 size_t n = cpy(buf, len, "[Function: ", 11); 1907 2025 n += cpy(buf + n, len - n, name, name_len); ··· 1910 2028 } 1911 2029 return cpy(buf, len, "[Function (anonymous)]", 22); 1912 2030 } 1913 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 2031 + jsval_t code_val = code_slot; 1914 2032 1915 2033 if (vtype(code_val) != T_STR) { 1916 2034 if (name && name_len > 0) { ··· 2813 2931 } 2814 2932 2815 2933 static void intern_init(void) { 2816 - if (INTERN_PROTO) return; 2817 - INTERN_PROTO = intern_string("__proto__", 9); 2934 + if (INTERN_LENGTH) return; 2818 2935 INTERN_LENGTH = intern_string("length", 6); 2819 2936 INTERN_PROTOTYPE = intern_string("prototype", 9); 2820 2937 INTERN_CONSTRUCTOR = intern_string("constructor", 11); ··· 2823 2940 INTERN_VALUE = intern_string("value", 5); 2824 2941 INTERN_GET = intern_string("get", 3); 2825 2942 INTERN_SET = intern_string("set", 3); 2826 - INTERN_CODE = intern_string("__code", 6); 2827 - INTERN_SCOPE = intern_string("__scope", 7); 2828 - INTERN_THIS = intern_string("__this", 6); 2829 - INTERN_NATIVE_FUNC = intern_string("__native_func", 13); 2830 - INTERN_ASYNC = intern_string("__async", 7); 2831 2943 INTERN_PROMISE = intern_string("promise", 7); 2832 - INTERN_BOUND_THIS = intern_string("__bound_this", 12); 2833 - INTERN_BOUND_ARGS = intern_string("__bound_args", 12); 2834 2944 INTERN_TARGET_FUNC = intern_string("__target_func", 13); 2835 2945 INTERN_ARGUMENTS = intern_string("arguments", 9); 2836 2946 INTERN_CALLEE = intern_string("callee", 6); ··· 2846 2956 INTERN_IDX[9] = intern_string("9", 1); 2847 2957 } 2848 2958 2849 - static inline uint32_t koff_hash(jsoff_t koff) { 2850 - return (koff >> 2) & (KOFF_BUCKETS - 1); 2851 - } 2852 - 2853 - #define KOFF_CACHE_SIZE 2048 2854 - typedef struct { 2855 - jsoff_t koff; 2856 - const char *interned; 2857 - } koff_cache_entry_t; 2858 - static koff_cache_entry_t koff_cache[KOFF_CACHE_SIZE]; 2859 - 2860 - static inline const char *get_koff_intern(jsoff_t koff) { 2861 - uint32_t slot = (koff >> 2) & (KOFF_CACHE_SIZE - 1); 2862 - if (koff_cache[slot].koff == koff) { 2863 - return koff_cache[slot].interned; 2864 - } 2865 - 2866 - uint32_t bucket = koff_hash(koff); 2867 - for (koff_intern_t *e = koff_buckets[bucket]; e; e = e->next) { 2868 - if (e->koff == koff) { 2869 - koff_cache[slot].koff = koff; 2870 - koff_cache[slot].interned = e->interned; 2871 - return e->interned; 2872 - } 2873 - } 2874 - return NULL; 2875 - } 2876 - 2877 - static inline void set_koff_intern(jsoff_t koff, const char *interned) { 2878 - uint32_t bucket = koff_hash(koff); 2879 - for (koff_intern_t *e = koff_buckets[bucket]; e; e = e->next) { 2880 - if (e->koff == koff) return; 2881 - } 2882 - koff_intern_t *entry = (koff_intern_t *)malloc(sizeof(koff_intern_t)); 2883 - if (!entry) return; 2884 - entry->koff = koff; 2885 - entry->interned = interned; 2886 - entry->next = koff_buckets[bucket]; 2887 - koff_buckets[bucket] = entry; 2888 - 2889 - uint32_t slot = (koff >> 2) & (KOFF_CACHE_SIZE - 1); 2890 - koff_cache[slot].koff = koff; 2891 - koff_cache[slot].interned = interned; 2892 - } 2893 - 2894 2959 static void invalidate_prop_cache(jsoff_t obj_offset) { 2895 2960 for (uint32_t i = 0; i < INTERN_PROP_CACHE_SIZE; i++) { 2896 2961 if (intern_prop_cache[i].obj_off == obj_offset) { ··· 2902 2967 } 2903 2968 2904 2969 static jsval_t mkprop(struct js *js, jsval_t obj, jsval_t k, jsval_t v, bool is_const) { 2970 + PERF_START(_mkprop_setup); 2905 2971 jsoff_t koff = (jsoff_t) vdata(k); 2906 2972 jsoff_t b, head = (jsoff_t) vdata(obj); 2907 2973 char buf[sizeof(koff) + sizeof(v)]; ··· 2912 2978 2913 2979 if (b & ARRMASK) brk |= ARRMASK; 2914 2980 memcpy(&js->mem[head], &brk, sizeof(brk)); 2981 + PERF_END(_mkprop_setup, perf_mkprop_setup_ns); 2915 2982 2983 + PERF_START(_mkprop_intern); 2916 2984 jsoff_t klen = (loadoff(js, koff) >> 2) - 1; 2917 2985 const char *p = (char *) &js->mem[koff + sizeof(koff)]; 2918 - const char *interned = intern_string(p, klen); 2919 - if (interned) set_koff_intern(koff, interned); 2986 + (void)intern_string(p, klen); /* Ensure key is interned for fast lookup later */ 2987 + PERF_END(_mkprop_intern, perf_mkprop_intern_ns); 2920 2988 2989 + PERF_START(_mkprop_mkentity); 2921 2990 jsoff_t prop_header = (b & ~(3U | CONSTMASK | ARRMASK | SLOTMASK)) | T_PROP; 2922 2991 if (is_const) prop_header |= CONSTMASK; 2923 - return mkentity(js, prop_header, buf, sizeof(buf)); 2992 + jsval_t result = mkentity(js, prop_header, buf, sizeof(buf)); 2993 + PERF_END(_mkprop_mkentity, perf_mkprop_mkentity_ns); 2994 + 2995 + perf_mkprop_count++; 2996 + return result; 2924 2997 } 2925 2998 2926 2999 static jsval_t mkslot(struct js *js, jsval_t obj, internal_slot_t slot, jsval_t v) { ··· 2949 3022 check: 2950 3023 if (next == 0 || next >= js->brk) return 0; 2951 3024 header = loadoff(js, next); 2952 - if ((header & SLOTMASK) == 0) return 0; 3025 + if ((header & SLOTMASK) == 0) goto advance; 2953 3026 koff = loadoff(js, next + sizeof(jsoff_t)); 2954 3027 if (koff == (jsoff_t)slot) return next; 3028 + advance: 2955 3029 next = header & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 2956 3030 goto check; 2957 3031 } ··· 2969 3043 return loadval(js, off + sizeof(jsoff_t) * 2); 2970 3044 } 2971 3045 3046 + static inline bool is_slot_prop(jsoff_t header) { 3047 + return (header & SLOTMASK) != 0; 3048 + } 3049 + 3050 + static inline jsoff_t next_prop(jsoff_t header) { 3051 + return header & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 3052 + } 3053 + 2972 3054 static jsval_t setup_func_prototype(struct js *js, jsval_t func) { 2973 3055 jsval_t proto_obj = mkobj(js, 0); 2974 3056 if (is_err(proto_obj)) return proto_obj; ··· 3010 3092 jsoff_t koff = (jsoff_t) vdata(k); 3011 3093 jsoff_t klen = offtolen(loadoff(js, koff)); 3012 3094 const char *key = (char *) &js->mem[koff + sizeof(jsoff_t)]; 3013 - if (streq(key, klen, "__proto__", 9)) { 3014 - return js_mkerr(js, "cannot assign to __proto__"); 3095 + if (streq(key, klen, STR_PROTO, STR_PROTO_LEN)) { 3096 + return js_mkerr(js, "cannot assign to " STR_PROTO); 3015 3097 } 3016 3098 3017 3099 if (vtype(obj) == T_ARR && streq(key, klen, "length", 6)) { ··· 3201 3283 } 3202 3284 3203 3285 jsval_t js_mksym(struct js *js, const char *desc) { 3204 - uint64_t id = ++js->symbol_counter; 3286 + uint64_t id = ++js->sym_counter; 3205 3287 jsoff_t desc_off = 0; 3206 3288 if (desc && *desc) { 3207 3289 jsval_t desc_str = js_mkstr(js, desc, strlen(desc)); ··· 3858 3940 } 3859 3941 3860 3942 static inline jsoff_t lkp_interned(struct js *js, jsval_t obj, const char *search_intern, size_t len) { 3943 + perf_lkp_calls++; 3944 + #if PERF_LKP_TRACE 3945 + if (perf_call_count >= 1 && perf_lkp_trace_count < 300) { 3946 + perf_lkp_trace_count++; 3947 + fprintf(stderr, "[LKP] '%.*s' on obj@%lu\n", (int)len, search_intern, (unsigned long)vdata(obj)); 3948 + } 3949 + #endif 3861 3950 jsoff_t obj_off = (jsoff_t)vdata(obj); 3862 3951 3863 3952 uint32_t cache_slot = (((uintptr_t)search_intern >> 3) ^ obj_off) & (INTERN_PROP_CACHE_SIZE - 1); 3864 3953 intern_prop_cache_entry_t *ce = &intern_prop_cache[cache_slot]; 3865 3954 if (ce->obj_off == obj_off && ce->intern_ptr == search_intern) { 3955 + perf_lkp_cache_hits++; 3866 3956 return ce->prop_off; 3867 3957 } 3868 3958 3869 3959 jsoff_t off = loadoff(js, obj_off) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 3870 3960 while (off < js->brk && off != 0) { 3961 + jsoff_t header = loadoff(js, off); 3962 + if (is_slot_prop(header)) { off = next_prop(header); continue; } 3963 + 3871 3964 jsoff_t koff = loadoff(js, (jsoff_t) (off + sizeof(off))); 3872 3965 jsoff_t klen = (loadoff(js, koff) >> 2) - 1; 3873 3966 if (klen == len) { 3874 - const char *stored_intern = get_koff_intern(koff); 3875 - if (stored_intern) { 3876 - if (stored_intern == search_intern) { 3877 - ce->obj_off = obj_off; 3878 - ce->intern_ptr = search_intern; 3879 - ce->prop_off = off; 3880 - return off; 3881 - } 3882 - } else { 3883 - const char *p = (char *) &js->mem[koff + sizeof(koff)]; 3884 - const char *new_intern = intern_string(p, klen); 3885 - if (new_intern) set_koff_intern(koff, new_intern); 3886 - if (new_intern == search_intern) { 3887 - ce->obj_off = obj_off; 3888 - ce->intern_ptr = search_intern; 3889 - ce->prop_off = off; 3890 - return off; 3891 - } 3967 + const char *p = (char *) &js->mem[koff + sizeof(koff)]; 3968 + if (intern_string(p, klen) == search_intern) { 3969 + perf_lkp_found_no_cache++; 3970 + ce->obj_off = obj_off; 3971 + ce->intern_ptr = search_intern; 3972 + ce->prop_off = off; 3973 + return off; 3892 3974 } 3893 3975 } 3894 - off = loadoff(js, off) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 3976 + off = next_prop(header); 3895 3977 } 3978 + perf_lkp_not_found++; 3896 3979 return 0; 3897 3980 } 3898 3981 ··· 3964 4047 if (t != T_OBJ && t != T_ARR && t != T_FUNC && t != T_PROMISE) return js_mknull(); 3965 4048 jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 3966 4049 3967 - jsoff_t off = lkp_interned(js, as_obj, INTERN_PROTO, 9); 3968 - if (off == 0) { 3969 - if (t == T_FUNC || t == T_ARR || t == T_PROMISE) return get_prototype_for_type(js, t); 3970 - return js_mknull(); 3971 - } 3972 - 3973 - jsval_t val = resolveprop(js, mkval(T_PROP, off)); 3974 - uint8_t vt = vtype(val); 4050 + jsval_t proto = get_slot(js, as_obj, SLOT_PROTO); 4051 + uint8_t pt = vtype(proto); 4052 + if (pt == T_OBJ || pt == T_ARR || pt == T_FUNC) return proto; 3975 4053 3976 - return (vt == T_OBJ || vt == T_ARR || vt == T_FUNC) ? val : js_mknull(); 4054 + if (t == T_FUNC || t == T_ARR || t == T_PROMISE) return get_prototype_for_type(js, t); 4055 + return js_mknull(); 3977 4056 } 3978 4057 3979 4058 static jsval_t get_proto(struct js *js, jsval_t obj) { ··· 3985 4064 if (t != T_OBJ && t != T_ARR && t != T_FUNC) return; 3986 4065 3987 4066 jsval_t as_obj = (t == T_OBJ) ? obj : mkval(T_OBJ, vdata(obj)); 3988 - jsval_t key = js_mkstr(js, "__proto__", 9); 3989 - jsoff_t existing = lkp_interned(js, as_obj, INTERN_PROTO, 9); 3990 - if (existing > 0) { 3991 - saveval(js, existing + sizeof(jsoff_t) * 2, proto); 3992 - } else { 3993 - mkprop(js, as_obj, key, proto, false); 3994 - } 4067 + set_slot(js, as_obj, SLOT_PROTO, proto); 3995 4068 } 3996 4069 3997 4070 static void set_proto(struct js *js, jsval_t obj, jsval_t proto) { ··· 4045 4118 static jsoff_t lkp_proto(struct js *js, jsval_t obj, const char *key, size_t len) { 4046 4119 uint8_t t = vtype(obj); 4047 4120 const char *key_intern = intern_string(key, len); 4121 + 4048 4122 if (!key_intern) return 0; 4049 - 4050 - if (key_intern == INTERN_PROTO) { 4051 - if (t == T_OBJ || t == T_ARR || t == T_FUNC) { 4052 - return lkp_interned(js, mkval(T_OBJ, vdata(obj)), key_intern, len); 4053 - } 4054 - return 0; 4055 - } 4123 + if (len == STR_PROTO_LEN && memcmp(key, STR_PROTO, STR_PROTO_LEN) == 0) return 0; 4056 4124 4057 4125 jsval_t cur = obj; 4058 4126 int depth = 0; ··· 4063 4131 jsoff_t off = lkp_interned(js, as_obj, key_intern, len); 4064 4132 if (off != 0) return off; 4065 4133 4066 - jsoff_t proto_off = lkp_interned(js, as_obj, INTERN_PROTO, 9); 4067 - if (proto_off == 0) { 4134 + jsval_t proto = get_slot(js, as_obj, SLOT_PROTO); 4135 + uint8_t pt = vtype(proto); 4136 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC) { 4068 4137 if (t == T_FUNC || t == T_ARR || t == T_PROMISE) { 4069 4138 cur = get_prototype_for_type(js, t); 4070 4139 t = vtype(cur); ··· 4074 4143 } 4075 4144 break; 4076 4145 } 4077 - cur = resolveprop(js, mkval(T_PROP, proto_off)); 4146 + cur = proto; 4078 4147 t = vtype(cur); 4079 4148 if (t == T_NULL || t == T_UNDEF) break; 4080 4149 depth++; ··· 4127 4196 key_str = decoded; 4128 4197 } 4129 4198 4199 + if (key_len == STR_PROTO_LEN && memcmp(key_str, STR_PROTO, STR_PROTO_LEN) == 0) { 4200 + jsval_t proto = get_slot(js, js->scope, SLOT_PROTO); 4201 + if (vtype(proto) != T_UNDEF) return proto; 4202 + return get_prototype_for_type(js, vtype(js->scope)); 4203 + } 4204 + 4130 4205 const char *key_intern = intern_string(key_str, key_len); 4131 4206 4132 4207 for (jsval_t scope = js->scope;;) { 4133 4208 jsoff_t off = lkp_interned(js, scope, key_intern, key_len); 4134 4209 if (off != 0) return mkval(T_PROP, off); 4135 4210 4136 - jsoff_t with_marker_off = lkp(js, scope, "__with_object__", 15); 4137 - if (with_marker_off != 0) { 4138 - jsval_t with_obj_val = resolveprop(js, mkval(T_PROP, with_marker_off)); 4139 - 4211 + jsval_t with_slot = get_slot(js, scope, SLOT_WITH); 4212 + if (vtype(with_slot) != T_UNDEF) { 4140 4213 jsval_t with_obj = ( 4141 - vtype(with_obj_val) == T_OBJ || 4142 - vtype(with_obj_val) == T_ARR || 4143 - vtype(with_obj_val) == T_FUNC) ? 4144 - with_obj_val : mkval(T_OBJ, vdata(with_obj_val) 4214 + vtype(with_slot) == T_OBJ || 4215 + vtype(with_slot) == T_ARR || 4216 + vtype(with_slot) == T_FUNC) ? 4217 + with_slot : mkval(T_OBJ, vdata(with_slot) 4145 4218 ); 4146 4219 4147 4220 jsoff_t prop_off = lkp_interned(js, with_obj, key_intern, key_len); ··· 4200 4273 4201 4274 static jsval_t resolveprop(struct js *js, jsval_t v) { 4202 4275 if (vtype(v) == T_PROPREF) { 4276 + if (is_prim_propref(v)) { 4277 + prim_propref_data_t *prim_data = prim_propref_get(v); 4278 + if (!prim_data) return js_mkundef(); 4279 + 4280 + jsval_t prim = prim_data->prim_val; 4281 + jsval_t key = mkval(T_STR, prim_data->key_off); 4282 + jsoff_t key_len; 4283 + const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 4284 + 4285 + jsval_t proto = get_prototype_for_type(js, vtype(prim)); 4286 + if (vtype(proto) == T_OBJ) { 4287 + jsval_t getter = js_mkundef(); 4288 + bool has_getter = false; 4289 + lkp_with_getter(js, proto, key_str, key_len, &getter, &has_getter); 4290 + if (has_getter && (vtype(getter) == T_FUNC || vtype(getter) == T_CFUNC)) { 4291 + js_parse_state_t saved; 4292 + JS_SAVE_STATE(js, saved); 4293 + uint8_t saved_flags = js->flags; 4294 + jsoff_t saved_toff = js->toff; 4295 + jsoff_t saved_tlen = js->tlen; 4296 + 4297 + push_this(prim); 4298 + jsval_t result = call_js_with_args(js, getter, NULL, 0); 4299 + pop_this(); 4300 + 4301 + JS_RESTORE_STATE(js, saved); 4302 + js->flags = saved_flags; 4303 + js->toff = saved_toff; 4304 + js->tlen = saved_tlen; 4305 + 4306 + return result; 4307 + } 4308 + 4309 + jsoff_t off = lkp_proto(js, prim, key_str, key_len); 4310 + if (off != 0) return resolveprop(js, mkval(T_PROP, off)); 4311 + } 4312 + 4313 + return js_mkundef(); 4314 + } 4315 + 4203 4316 jsoff_t obj_off = propref_obj(v); 4204 4317 jsoff_t key_off = propref_key(v); 4205 4318 jsval_t key = mkval(T_STR, key_off); ··· 4273 4386 4274 4387 static jsval_t assign(struct js *js, jsval_t lhs, jsval_t val) { 4275 4388 if (vtype(lhs) == T_PROPREF) { 4389 + if (is_prim_propref(lhs)) { 4390 + prim_propref_data_t *prim_data = prim_propref_get(lhs); 4391 + if (!prim_data) { 4392 + if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot create property on primitive value"); 4393 + return val; 4394 + } 4395 + 4396 + jsval_t prim = prim_data->prim_val; 4397 + jsval_t key = mkval(T_STR, prim_data->key_off); 4398 + jsoff_t key_len; 4399 + const char *key_str = (const char *)&js->mem[vstr(js, key, &key_len)]; 4400 + 4401 + jsval_t proto = get_prototype_for_type(js, vtype(prim)); 4402 + if (vtype(proto) == T_OBJ) { 4403 + jsval_t setter = js_mkundef(); 4404 + bool has_setter = false; 4405 + lkp_with_setter(js, proto, key_str, key_len, &setter, &has_setter); 4406 + if (has_setter && (vtype(setter) == T_FUNC || vtype(setter) == T_CFUNC)) { 4407 + js_parse_state_t saved; 4408 + JS_SAVE_STATE(js, saved); 4409 + uint8_t saved_flags = js->flags; 4410 + jsoff_t saved_toff = js->toff; 4411 + jsoff_t saved_tlen = js->tlen; 4412 + 4413 + push_this(prim); 4414 + jsval_t result = call_js_with_args(js, setter, &val, 1); 4415 + pop_this(); 4416 + 4417 + JS_RESTORE_STATE(js, saved); 4418 + js->flags = saved_flags; 4419 + js->toff = saved_toff; 4420 + js->tlen = saved_tlen; 4421 + 4422 + return is_err(result) ? result : val; 4423 + } 4424 + } 4425 + 4426 + if (js->flags & F_STRICT) { 4427 + return js_mkerr_typed( 4428 + js, JS_ERR_TYPE, "Cannot create property '%.*s' on %s", 4429 + (int)key_len, key_str, typestr(vtype(prim)) 4430 + ); 4431 + } 4432 + return val; 4433 + } 4434 + 4276 4435 jsoff_t obj_off = propref_obj(lhs); 4277 4436 jsoff_t key_off = propref_key(lhs); 4278 4437 jsval_t obj = mkval(is_arr_off(js, obj_off) ? T_ARR : T_OBJ, obj_off); ··· 4533 4692 } 4534 4693 4535 4694 if (t == T_STR || t == T_NUM || t == T_BOOL || t == T_BIGINT) { 4536 - jsoff_t off = lkp_proto(js, l, ptr, plen); 4537 - if (off != 0) { 4538 - return resolveprop(js, mkval(T_PROP, off)); 4539 - } 4540 - return js_mkundef(); 4695 + jsval_t key = js_mkstr(js, ptr, plen); 4696 + return mkprim_propref(l, (jsoff_t)vdata(key)); 4541 4697 } 4542 4698 4543 4699 if (t == T_PROMISE) { ··· 4613 4769 if ((streq(ptr, plen, "callee", 6) || streq(ptr, plen, "caller", 6)) && 4614 4770 lkp(js, l, "__strict_args__", 15) != 0) { 4615 4771 return js_mkerr_typed(js, JS_ERR_TYPE, "'%.*s' not allowed on strict arguments", (int)plen, ptr); 4772 + } 4773 + 4774 + if (plen == STR_PROTO_LEN && memcmp(ptr, STR_PROTO, STR_PROTO_LEN) == 0) { 4775 + jsval_t proto = get_slot(js, l, SLOT_PROTO); 4776 + if (vtype(proto) != T_UNDEF) return proto; 4777 + return get_prototype_for_type(js, t); 4616 4778 } 4617 4779 4618 4780 jsoff_t own_off = lkp(js, l, ptr, plen); ··· 4972 5134 static void setup_arguments(struct js *js, jsval_t scope, jsval_t *args, int nargs, bool strict) { 4973 5135 if (vtype(js->current_func) == T_FUNC) { 4974 5136 jsval_t func_obj = mkval(T_OBJ, vdata(js->current_func)); 4975 - if (lkp_interned(js, func_obj, INTERN_THIS, 6) != 0) return; 5137 + if (vtype(get_slot(js, func_obj, SLOT_THIS)) != T_UNDEF) return; 4976 5138 } 4977 5139 4978 5140 jsval_t arguments_obj = mkobj(js, 0); ··· 5068 5230 return js_mkerr(js, "failed to parse function"); 5069 5231 } 5070 5232 5233 + /* ===== PHASE 4: BIND PHASE (instrumented) ===== */ 5234 + PERF_START(_p4_total); 5235 + 5236 + /* Sub1: Parameter binding loop */ 5237 + PERF_START(_p4_sub1); 5071 5238 int argi = 0; 5072 5239 for (int i = 0; i < pf->param_count; i++) { 5073 5240 parsed_param_t *pp = (parsed_param_t *)utarray_eltptr(pf->params, i); ··· 5096 5263 setprop_fast(js, function_scope, &fn[pp->name_off], pp->name_len, v); 5097 5264 } 5098 5265 } 5266 + PERF_END(_p4_sub1, perf_phase4_sub1_ns); 5099 5267 5268 + /* Sub2: Rest parameter handling */ 5269 + PERF_START(_p4_sub2); 5100 5270 if (pf->has_rest && pf->rest_param_len > 0) { 5101 5271 jsval_t rest_array = mkarr(js); 5102 5272 if (!is_err(rest_array)) { ··· 5119 5289 setprop(js, function_scope, js_mkstr(js, &fn[pf->rest_param_start], pf->rest_param_len), rest_array); 5120 5290 } 5121 5291 } 5292 + PERF_END(_p4_sub2, perf_phase4_sub2_ns); 5122 5293 5294 + /* Sub3: code_uses_arguments check (THIS IS SUSPECT!) */ 5295 + PERF_START(_p4_sub3); 5296 + bool needs_arguments = code_uses_arguments(&fn[pf->body_start], pf->body_len); 5297 + PERF_END(_p4_sub3, perf_phase4_sub3_ns); 5298 + 5299 + /* Sub4: setup_arguments if needed */ 5300 + PERF_START(_p4_sub4); 5123 5301 bool func_strict = pf->is_strict; 5124 5302 5125 5303 if (!func_strict && vtype(func_val) == T_FUNC) { 5126 5304 jsval_t func_obj = mkval(T_OBJ, vdata(func_val)); 5127 - jsoff_t strict_off = lkp(js, func_obj, "__strict", 8); 5128 - if (strict_off != 0) { 5129 - jsval_t strict_val = resolveprop(js, mkval(T_PROP, strict_off)); 5130 - func_strict = (vtype(strict_val) == T_BOOL && vdata(strict_val) == 1); 5131 - } 5305 + jsval_t strict_slot = get_slot(js, func_obj, SLOT_STRICT); 5306 + func_strict = (vtype(strict_slot) == T_BOOL && vdata(strict_slot) == 1); 5132 5307 } 5133 5308 5134 - if (code_uses_arguments(&fn[pf->body_start], pf->body_len)) { 5309 + if (needs_arguments) { 5135 5310 setup_arguments(js, function_scope, args, argc, func_strict); 5136 5311 } 5312 + PERF_END(_p4_sub4, perf_phase4_sub4_ns); 5137 5313 5314 + /* Sub5: NFE name binding */ 5315 + PERF_START(_p4_sub5); 5138 5316 if (vtype(func_name) == T_STR && vtype(func_val) == T_FUNC) { 5317 + PERF_START(_sub5_vstr); 5139 5318 jsoff_t len; 5140 5319 (void)vstr(js, func_name, &len); 5320 + PERF_END(_sub5_vstr, perf_sub5_vstr_ns); 5141 5321 if (len > 0) { 5322 + PERF_START(_sub5_mkprop); 5142 5323 jsval_t prop = mkprop(js, function_scope, func_name, func_val, true); 5324 + PERF_END(_sub5_mkprop, perf_sub5_mkprop_ns); 5143 5325 (void)prop; 5326 + perf_sub5_count++; 5144 5327 } 5145 5328 } 5329 + PERF_END(_p4_sub5, perf_phase4_sub5_ns); 5146 5330 5331 + /* Sub6: Strict mode + this handling */ 5332 + PERF_START(_p4_sub6); 5147 5333 if (func_strict && (vtype(target_this) == T_UNDEF || vtype(target_this) == T_NULL || 5148 5334 (vtype(target_this) == T_OBJ && vdata(target_this) == 0))) { 5149 5335 js->this_val = js_mkundef(); ··· 5151 5337 js->this_val = target_this; 5152 5338 } 5153 5339 js->flags = F_CALL | (func_strict ? F_STRICT : 0); 5340 + PERF_END(_p4_sub6, perf_phase4_sub6_ns); 5341 + 5342 + PERF_END(_p4_total, perf_phase4_ns); 5343 + PERF_CALL_INC(); 5344 + if (PERF_SHOULD_REPORT()) perf_report(js->brk); 5345 + /* ===== END PHASE 4 ===== */ 5154 5346 5155 5347 jsval_t res = js_eval(js, &fn[pf->body_start], pf->body_len); 5156 5348 if (!is_err(res) && !(js->flags & F_RETURN)) res = js_mkundef(); ··· 5179 5371 int combined_nargs = nargs; 5180 5372 int bound_argc = 0; 5181 5373 5182 - jsoff_t bound_args_off = lkp_interned(js, func_obj, INTERN_BOUND_ARGS, 12); 5183 - if (bound_args_off != 0) { 5184 - jsval_t bound_arr = resolveprop(js, mkval(T_PROP, bound_args_off)); 5185 - if (vtype(bound_arr) == T_ARR) { 5186 - jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 5187 - if (len_off != 0) { 5188 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 5189 - if (vtype(len_val) == T_NUM) { 5190 - bound_argc = (int) tod(len_val); 5191 - } 5374 + jsval_t bound_arr = get_slot(js, func_obj, SLOT_BOUND_ARGS); 5375 + if (vtype(bound_arr) == T_ARR) { 5376 + jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 5377 + if (len_off != 0) { 5378 + jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 5379 + if (vtype(len_val) == T_NUM) { 5380 + bound_argc = (int) tod(len_val); 5192 5381 } 5193 - 5194 - if (bound_argc > 0) { 5195 - combined_nargs = bound_argc + nargs; 5196 - combined_args = (jsval_t *)ANT_GC_MALLOC(sizeof(jsval_t) * combined_nargs); 5197 - if (combined_args) { 5198 - for (int i = 0; i < bound_argc; i++) { 5199 - char idx[16]; 5200 - snprintf(idx, sizeof(idx), "%d", i); 5201 - jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 5202 - combined_args[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 5203 - } 5204 - for (int i = 0; i < nargs; i++) { 5205 - combined_args[bound_argc + i] = args[i]; 5206 - } 5207 - args = combined_args; 5208 - nargs = combined_nargs; 5382 + } 5383 + 5384 + if (bound_argc > 0) { 5385 + combined_nargs = bound_argc + nargs; 5386 + combined_args = (jsval_t *)ANT_GC_MALLOC(sizeof(jsval_t) * combined_nargs); 5387 + if (combined_args) { 5388 + for (int i = 0; i < bound_argc; i++) { 5389 + char idx[16]; 5390 + snprintf(idx, sizeof(idx), "%d", i); 5391 + jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 5392 + combined_args[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 5393 + } 5394 + for (int i = 0; i < nargs; i++) { 5395 + combined_args[bound_argc + i] = args[i]; 5209 5396 } 5397 + args = combined_args; 5398 + nargs = combined_nargs; 5210 5399 } 5211 5400 } 5212 5401 } 5213 5402 5214 - jsoff_t native_off = lkp_interned(js, func_obj, INTERN_NATIVE_FUNC, 13); 5215 - if (native_off != 0) { 5216 - jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 5217 - if (vtype(native_val) == T_CFUNC) { 5218 - jsoff_t this_off = lkp_interned(js, func_obj, INTERN_BOUND_THIS, 12); 5219 - jsval_t bound_this = js_mkundef(); 5220 - if (this_off != 0) { 5221 - bound_this = resolveprop(js, mkval(T_PROP, this_off)); 5222 - } 5223 - 5224 - jsval_t saved_this = js->this_val; 5225 - if (vtype(bound_this) != JS_UNDEF) { 5226 - push_this(bound_this); 5227 - js->this_val = bound_this; 5228 - } 5229 - 5230 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(native_val); 5231 - jsval_t result = fn(js, args, nargs); 5232 - 5233 - if (vtype(bound_this) != JS_UNDEF) { 5234 - pop_this(); 5235 - js->this_val = saved_this; 5236 - } 5237 - 5238 - if (combined_args) ANT_GC_FREE(combined_args); 5239 - return result; 5403 + jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 5404 + if (vtype(cfunc_slot) == T_CFUNC) { 5405 + jsval_t bound_this = get_slot(js, func_obj, SLOT_BOUND_THIS); 5406 + 5407 + jsval_t saved_this = js->this_val; 5408 + if (vtype(bound_this) != JS_UNDEF) { 5409 + push_this(bound_this); 5410 + js->this_val = bound_this; 5240 5411 } 5241 - } 5242 - 5243 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 5244 - if (code_off == 0) { 5412 + 5413 + jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot); 5414 + jsval_t result = fn(js, args, nargs); 5415 + 5416 + if (vtype(bound_this) != JS_UNDEF) { 5417 + pop_this(); 5418 + js->this_val = saved_this; 5419 + } 5420 + 5245 5421 if (combined_args) ANT_GC_FREE(combined_args); 5246 - return js_mkerr(js, "function has no code"); 5422 + return result; 5247 5423 } 5248 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 5424 + 5425 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 5249 5426 if (vtype(code_val) != T_STR) { 5250 5427 if (combined_args) ANT_GC_FREE(combined_args); 5251 - return js_mkerr(js, "function code not string"); 5428 + return js_mkerr(js, "function has no code"); 5252 5429 } 5253 5430 5254 5431 jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 5255 5432 const char *fn = (const char *) (&js->mem[fnoff]); 5256 5433 5257 - jsval_t closure_scope = js_mkundef(); 5258 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 5259 - if (scope_off != 0) { 5260 - closure_scope = resolveprop(js, mkval(T_PROP, scope_off)); 5261 - } 5434 + jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 5262 5435 5263 - jsoff_t this_off = lkp_interned(js, func_obj, INTERN_THIS, 6); 5264 - if (this_off != 0) { 5265 - jsval_t captured_this = resolveprop(js, mkval(T_PROP, this_off)); 5436 + jsval_t captured_this = get_slot(js, func_obj, SLOT_THIS); 5437 + if (vtype(captured_this) != T_UNDEF) { 5266 5438 pop_this(); 5267 5439 push_this(captured_this); 5268 5440 } 5269 5441 5270 - jsoff_t bound_this_off = lkp_interned(js, func_obj, INTERN_BOUND_THIS, 12); 5271 - if (bound_this_off != 0) { 5272 - jsval_t bound_this = resolveprop(js, mkval(T_PROP, bound_this_off)); 5442 + jsval_t bound_this = get_slot(js, func_obj, SLOT_BOUND_THIS); 5443 + if (vtype(bound_this) != T_UNDEF) { 5273 5444 pop_this(); 5274 5445 push_this(bound_this); 5275 5446 } ··· 5473 5644 } 5474 5645 5475 5646 jsval_t target_this = peek_this(); 5476 - bool is_constructor_call = (vtype(target_this) == T_OBJ && lkp_interned(js, target_this, INTERN_PROTO, 9) == 0); 5647 + jsval_t target_proto = (vtype(target_this) == T_OBJ) ? get_slot(js, target_this, SLOT_PROTO) : js_mkundef(); 5648 + bool is_constructor_call = (vtype(target_this) == T_OBJ && vtype(target_proto) == T_UNDEF); 5477 5649 5478 5650 if (vtype(func) == T_FUNC && vtype(target_this) == T_OBJ) { 5479 - jsoff_t proto_check = lkp_interned(js, target_this, INTERN_PROTO, 9); 5480 - if (proto_check == 0) { 5651 + if (vtype(target_proto) == T_UNDEF) { 5481 5652 jsval_t func_obj = mkval(T_OBJ, vdata(func)); 5482 5653 5483 5654 jsoff_t target_func_off = lkp_interned(js, func_obj, INTERN_TARGET_FUNC, 13); ··· 5509 5680 5510 5681 if (vtype(func) == T_FUNC) { 5511 5682 jsval_t func_obj = mkval(T_OBJ, vdata(func)); 5512 - jsoff_t native_off = lkp_interned(js, func_obj, INTERN_NATIVE_FUNC, 13); 5513 - if (native_off != 0) { 5514 - jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 5515 - if (vtype(native_val) == T_CFUNC) { 5516 - jsval_t saved_func = js->current_func; 5517 - js->current_func = func; 5518 - res = call_c(js, (jsval_t(*)(struct js *, jsval_t *, int)) vdata(native_val)); 5519 - js->current_func = saved_func; 5520 - } 5683 + jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 5684 + if (vtype(cfunc_slot) == T_CFUNC) { 5685 + jsval_t saved_func = js->current_func; 5686 + js->current_func = func; 5687 + res = call_c(js, (jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot)); 5688 + js->current_func = saved_func; 5521 5689 } else { 5522 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 5523 - if (code_off == 0) return js_mkerr(js, "function has no code"); 5524 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 5525 - if (vtype(code_val) != T_STR) return js_mkerr(js, "function code not string"); 5526 - jsval_t closure_scope = js_mkundef(); 5527 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 5528 - if (scope_off != 0) { 5529 - closure_scope = resolveprop(js, mkval(T_PROP, scope_off)); 5530 - } 5690 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 5691 + if (vtype(code_val) != T_STR) return js_mkerr(js, "function has no code"); 5692 + jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 5531 5693 jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 5532 5694 const char *code_str = (const char *) (&js->mem[fnoff]); 5533 - bool is_async = false; 5534 - jsoff_t async_off = lkp_interned(js, func_obj, INTERN_ASYNC, 7); 5535 - if (async_off != 0) { 5536 - jsval_t async_val = resolveprop(js, mkval(T_PROP, async_off)); 5537 - is_async = vtype(async_val) == T_BOOL && vdata(async_val) == 1; 5538 - } 5695 + jsval_t async_slot = get_slot(js, func_obj, SLOT_ASYNC); 5696 + bool is_async = vtype(async_slot) == T_BOOL && vdata(async_slot) == 1; 5539 5697 5540 5698 jsval_t captured_this = js_mkundef(); 5541 5699 bool is_arrow = false; 5542 5700 bool is_bound = false; 5543 5701 5544 - jsoff_t this_off = lkp_interned(js, func_obj, INTERN_THIS, 6); 5545 - if (this_off != 0) { 5546 - captured_this = resolveprop(js, mkval(T_PROP, this_off)); 5702 + jsval_t this_slot = get_slot(js, func_obj, SLOT_THIS); 5703 + if (vtype(this_slot) != T_UNDEF) { 5704 + captured_this = this_slot; 5547 5705 is_arrow = true; 5548 5706 } 5549 5707 5550 - jsoff_t bound_this_off = lkp_interned(js, func_obj, INTERN_BOUND_THIS, 12); 5551 - if (bound_this_off != 0 && !is_constructor_call) { 5552 - captured_this = resolveprop(js, mkval(T_PROP, bound_this_off)); 5708 + jsval_t bound_this_slot = get_slot(js, func_obj, SLOT_BOUND_THIS); 5709 + if (vtype(bound_this_slot) != T_UNDEF && !is_constructor_call) { 5710 + captured_this = bound_this_slot; 5553 5711 is_bound = true; 5554 5712 } 5555 5713 5556 5714 jsval_t bound_args_storage[64]; 5557 5715 jsval_t *bound_args = NULL; 5558 5716 int bound_argc = 0; 5559 - jsoff_t bound_args_off = lkp_interned(js, func_obj, INTERN_BOUND_ARGS, 12); 5560 - if (bound_args_off != 0) { 5561 - jsval_t bound_arr = resolveprop(js, mkval(T_PROP, bound_args_off)); 5562 - if (vtype(bound_arr) == T_ARR) { 5563 - jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 5564 - if (len_off != 0) { 5565 - jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 5566 - if (vtype(len_val) == T_NUM) { 5567 - bound_argc = (int) tod(len_val); 5568 - if (bound_argc > 64) bound_argc = 64; 5569 - } 5717 + jsval_t bound_arr = get_slot(js, func_obj, SLOT_BOUND_ARGS); 5718 + if (vtype(bound_arr) == T_ARR) { 5719 + jsoff_t len_off = lkp_interned(js, bound_arr, INTERN_LENGTH, 6); 5720 + if (len_off != 0) { 5721 + jsval_t len_val = resolveprop(js, mkval(T_PROP, len_off)); 5722 + if (vtype(len_val) == T_NUM) { 5723 + bound_argc = (int) tod(len_val); 5724 + if (bound_argc > 64) bound_argc = 64; 5570 5725 } 5571 - if (bound_argc > 0) { 5572 - bound_args = bound_args_storage; 5573 - for (int i = 0; i < bound_argc; i++) { 5574 - char idx[16]; 5575 - snprintf(idx, sizeof(idx), "%d", i); 5576 - jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 5577 - bound_args[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 5578 - } 5726 + } 5727 + if (bound_argc > 0) { 5728 + bound_args = bound_args_storage; 5729 + for (int i = 0; i < bound_argc; i++) { 5730 + char idx[16]; 5731 + snprintf(idx, sizeof(idx), "%d", i); 5732 + jsoff_t prop_off = lkp(js, bound_arr, idx, strlen(idx)); 5733 + bound_args[i] = (prop_off != 0) ? resolveprop(js, mkval(T_PROP, prop_off)) : js_mkundef(); 5579 5734 } 5580 5735 } 5581 5736 } ··· 5650 5805 push_this(captured_this); 5651 5806 } 5652 5807 5653 - jsoff_t count_off = lkp(js, func_obj, "__field_count", 13); 5654 - if (count_off == 0 || vtype(target_this) != T_OBJ) goto skip_fields; 5655 - 5656 - jsval_t count_val = resolveprop(js, mkval(T_PROP, count_off)); 5657 - if (vtype(count_val) != T_NUM) goto skip_fields; 5808 + jsval_t count_val = get_slot(js, func_obj, SLOT_FIELD_COUNT); 5809 + if (vtype(count_val) != T_NUM || vtype(target_this) != T_OBJ) goto skip_fields; 5658 5810 5659 5811 int field_count = (int)tod(count_val); 5660 5812 jsoff_t src_off = lkp(js, func_obj, "__source", 8); ··· 5738 5890 result = ((jsval_t (*)(struct js *, jsval_t *, int))vdata(ts_func))(js, NULL, 0); 5739 5891 } else { 5740 5892 jsval_t func_obj = mkval(T_OBJ, vdata(ts_func)); 5741 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 5742 - if (code_off == 0) goto restore_fallback; 5743 - 5744 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 5893 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 5745 5894 if (vtype(code_val) != T_STR) goto restore_fallback; 5746 5895 5747 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 5748 - jsval_t closure_scope = scope_off ? resolveprop(js, mkval(T_PROP, scope_off)) : js->scope; 5896 + jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 5897 + if (vtype(closure_scope) == T_UNDEF) closure_scope = js->scope; 5749 5898 5750 5899 jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 5751 5900 const char *code_str = (const char *)&js->mem[fnoff]; ··· 5795 5944 jsval_t prop = setprop(js, global_scope, key, r); 5796 5945 if (is_err(prop)) return prop; 5797 5946 return r; 5947 + } 5948 + if ((js->flags & F_STRICT) && vtype(lhs) == T_UNDEF) { 5949 + return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot create property on primitive value"); 5798 5950 } 5799 5951 return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid left-hand side in assignment"); 5800 5952 } ··· 6692 6844 if (st != T_OBJ && st != T_ARR && st != T_FUNC) goto spread_next; 6693 6845 6694 6846 jsval_t src_obj = (st == T_OBJ) ? spread_obj : mkval(T_OBJ, vdata(spread_obj)); 6695 - jsoff_t next_prop = loadoff(js, (jsoff_t) vdata(src_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 6847 + jsoff_t next_prop_off = loadoff(js, (jsoff_t) vdata(src_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 6696 6848 6697 - while (next_prop < js->brk && next_prop != 0) { 6698 - jsoff_t koff = loadoff(js, next_prop + (jsoff_t) sizeof(next_prop)); 6849 + while (next_prop_off < js->brk && next_prop_off != 0) { 6850 + jsoff_t header = loadoff(js, next_prop_off); 6851 + if (is_slot_prop(header)) { next_prop_off = next_prop(header); continue; } 6852 + 6853 + jsoff_t koff = loadoff(js, next_prop_off + (jsoff_t) sizeof(next_prop_off)); 6699 6854 jsoff_t klen = offtolen(loadoff(js, koff)); 6700 6855 const char *prop_key = (char *) &js->mem[koff + sizeof(koff)]; 6701 - jsval_t prop_val = loadval(js, next_prop + (jsoff_t) (sizeof(next_prop) + sizeof(koff))); 6856 + jsval_t prop_val = loadval(js, next_prop_off + (jsoff_t) (sizeof(next_prop_off) + sizeof(koff))); 6702 6857 6703 - next_prop = loadoff(js, next_prop) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 6858 + next_prop_off = next_prop(header); 6704 6859 if (is_internal_prop(prop_key, klen)) continue; 6705 6860 6706 6861 jsval_t key_str = js_mkstr(js, prop_key, klen); ··· 6866 7021 jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 6867 7022 jsval_t func_obj = mkobj(js, 0); 6868 7023 if (is_err(func_obj)) return func_obj; 6869 - jsval_t code_key = js_mkstr(js, "__code", 6); 6870 - setprop(js, func_obj, code_key, str); 7024 + set_slot(js, func_obj, SLOT_CODE, str); 6871 7025 jsval_t name_key = js_mkstr(js, "name", 4); 6872 7026 setprop(js, func_obj, name_key, key); 6873 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 6874 - setprop(js, func_obj, scope_key, js->scope); 7027 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 6875 7028 jsval_t val = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 6876 7029 6877 7030 if (is_getter || is_setter) { ··· 7040 7193 js->consumed = 1; 7041 7194 jsval_t func_obj = mkobj(js, 0); 7042 7195 if (is_err(func_obj)) return func_obj; 7043 - jsval_t code_key = js_mkstr(js, "__code", 6); 7044 - if (is_err(code_key)) return code_key; 7045 - jsval_t res2 = setprop(js, func_obj, code_key, str); 7046 - if (is_err(res2)) return res2; 7196 + set_slot(js, func_obj, SLOT_CODE, str); 7047 7197 7048 7198 jsval_t len_key = js_mkstr(js, "length", 6); 7049 7199 if (is_err(len_key)) return len_key; ··· 7052 7202 js_set_descriptor(js, func_obj, "length", 6, JS_DESC_C); 7053 7203 7054 7204 if (is_async) { 7055 - jsval_t async_key = js_mkstr(js, "__async", 7); 7056 - if (is_err(async_key)) return async_key; 7057 - jsval_t res_async = setprop(js, func_obj, async_key, js_mktrue()); 7058 - if (is_err(res_async)) return res_async; 7205 + set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 7059 7206 } 7060 7207 7061 7208 if (name_len > 0) { ··· 7068 7215 } 7069 7216 7070 7217 if (!(flags & F_NOEXEC)) { 7071 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 7072 - if (is_err(scope_key)) return scope_key; 7073 - jsval_t res4 = setprop(js, func_obj, scope_key, js->scope); 7074 - if (is_err(res4)) return res4; 7218 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 7075 7219 7076 7220 if (flags & F_STRICT) { 7077 - jsval_t strict_key = js_mkstr(js, "__strict", 8); 7078 - if (is_err(strict_key)) return strict_key; 7079 - jsval_t res_strict = setprop(js, func_obj, strict_key, js_mktrue()); 7080 - if (is_err(res_strict)) return res_strict; 7221 + set_slot(js, func_obj, SLOT_STRICT, js_mktrue()); 7081 7222 } 7082 7223 } 7083 7224 ··· 7234 7375 if (is_err(str)) return str; 7235 7376 jsval_t func_obj = mkobj(js, 0); 7236 7377 if (is_err(func_obj)) return func_obj; 7237 - jsval_t code_key = js_mkstr(js, "__code", 6); 7238 - if (is_err(code_key)) return code_key; 7239 - jsval_t res = setprop(js, func_obj, code_key, str); 7240 - if (is_err(res)) return res; 7241 - jsval_t async_key = js_mkstr(js, "__async", 7); 7242 - if (is_err(async_key)) return async_key; 7243 - jsval_t res_async = setprop(js, func_obj, async_key, js_mktrue()); 7244 - if (is_err(res_async)) return res_async; 7378 + set_slot(js, func_obj, SLOT_CODE, str); 7379 + set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 7245 7380 if (!(flags & F_NOEXEC)) { 7246 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 7247 - if (is_err(scope_key)) return scope_key; 7248 - jsval_t res2 = setprop(js, func_obj, scope_key, js->scope); 7249 - if (is_err(res2)) return res2; 7381 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 7250 7382 } 7251 7383 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); 7252 7384 } ··· 7371 7503 jsval_t func_obj = mkobj(js, 0); 7372 7504 if (is_err(func_obj)) return func_obj; 7373 7505 7374 - jsval_t code_key = js_mkstr(js, "__code", 6); 7375 - if (is_err(code_key)) return code_key; 7376 - 7377 - jsval_t res = setprop(js, func_obj, code_key, str); 7378 - if (is_err(res)) return res; 7506 + set_slot(js, func_obj, SLOT_CODE, str); 7379 7507 7380 7508 if (is_async) { 7381 - jsval_t async_key = js_mkstr(js, "__async", 7); 7382 - if (is_err(async_key)) return async_key; 7383 - jsval_t res_async = setprop(js, func_obj, async_key, js_mktrue()); 7384 - if (is_err(res_async)) return res_async; 7509 + set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 7385 7510 } 7386 7511 7387 7512 if (!(flags & F_NOEXEC)) { 7388 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 7389 - if (is_err(scope_key)) return scope_key; 7390 - jsval_t res2 = setprop(js, func_obj, scope_key, js->scope); 7391 - if (is_err(res2)) return res2; 7392 - 7393 - jsval_t this_key = js_mkstr(js, "__this", 6); 7394 - if (is_err(this_key)) return this_key; 7395 - jsval_t res3 = setprop(js, func_obj, this_key, js->this_val); 7396 - if (is_err(res3)) return res3; 7513 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 7514 + set_slot(js, func_obj, SLOT_THIS, js->this_val); 7397 7515 } 7398 7516 7399 7517 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); ··· 7835 7953 coro->is_ready = false; 7836 7954 7837 7955 jsval_t resume_obj = mkobj(js, 0); 7838 - setprop(js, resume_obj, js_mkstr(js, "__native_func", 13), js_mkfun(resume_coroutine_wrapper)); 7839 - setprop(js, resume_obj, js_mkstr(js, "__coroutine", 11), tov((double)(uintptr_t)coro)); 7956 + set_slot(js, resume_obj, SLOT_CFUNC, js_mkfun(resume_coroutine_wrapper)); 7957 + set_slot(js, resume_obj, SLOT_CORO, tov((double)(uintptr_t)coro)); 7840 7958 jsval_t resume_fn = mkval(T_FUNC, vdata(resume_obj)); 7841 7959 7842 7960 jsval_t reject_obj = mkobj(js, 0); 7843 - setprop(js, reject_obj, js_mkstr(js, "__native_func", 13), js_mkfun(reject_coroutine_wrapper)); 7844 - setprop(js, reject_obj, js_mkstr(js, "__coroutine", 11), tov((double)(uintptr_t)coro)); 7961 + set_slot(js, reject_obj, SLOT_CFUNC, js_mkfun(reject_coroutine_wrapper)); 7962 + set_slot(js, reject_obj, SLOT_CORO, tov((double)(uintptr_t)coro)); 7845 7963 jsval_t reject_fn = mkval(T_FUNC, vdata(reject_obj)); 7846 7964 7847 7965 jsval_t then_args[] = { resume_fn, reject_fn }; ··· 8115 8233 jsval_t func_obj = mkobj(js, 0); 8116 8234 if (is_err(func_obj)) return func_obj; 8117 8235 8118 - jsval_t code_key = js_mkstr(js, "__code", 6); 8119 - if (is_err(code_key)) return code_key; 8120 - 8121 - jsval_t res2 = setprop(js, func_obj, code_key, str); 8122 - if (is_err(res2)) return res2; 8236 + set_slot(js, func_obj, SLOT_CODE, str); 8123 8237 8124 8238 if (!(flags & F_NOEXEC)) { 8125 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 8126 - if (is_err(scope_key)) return scope_key; 8127 - jsval_t res3 = setprop(js, func_obj, scope_key, js->scope); 8128 - if (is_err(res3)) return res3; 8129 - 8130 - jsval_t this_key = js_mkstr(js, "__this", 6); 8131 - if (is_err(this_key)) return this_key; 8132 - jsval_t res4 = setprop(js, func_obj, this_key, js->this_val); 8133 - if (is_err(res4)) return res4; 8239 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 8240 + set_slot(js, func_obj, SLOT_THIS, js->this_val); 8134 8241 } 8135 8242 8136 8243 return mkval(T_FUNC, (unsigned long) vdata(func_obj)); ··· 8289 8396 if (is_err(rest_obj)) return rest_obj; 8290 8397 jsoff_t scan = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8291 8398 while (scan < js->brk && scan != 0) { 8399 + jsoff_t header = loadoff(js, scan); 8400 + if (is_slot_prop(header)) { scan = next_prop(header); continue; } 8401 + 8292 8402 jsoff_t koff = loadoff(js, scan + (jsoff_t) sizeof(scan)); 8293 8403 jsoff_t klen = offtolen(loadoff(js, koff)); 8294 8404 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 8300 8410 jsoff_t pklen, pkoff = vstr(js, pk, &pklen); 8301 8411 if (klen == pklen && memcmp(key, &js->mem[pkoff], klen) == 0) { is_picked = true; break; } 8302 8412 } 8303 - if (!is_picked && !(klen == 9 && memcmp(key, "__proto__", 9) == 0)) { 8413 + if (!is_picked && !(klen == STR_PROTO_LEN && memcmp(key, STR_PROTO, STR_PROTO_LEN) == 0)) { 8304 8414 jsval_t val = loadval(js, scan + (jsoff_t) (sizeof(scan) + sizeof(koff))); 8305 8415 jsval_t key_str = js_mkstr(js, key, klen); 8306 8416 if (is_err(key_str)) return key_str; 8307 8417 jsval_t res = setprop(js, rest_obj, key_str, val); 8308 8418 if (is_err(res)) return res; 8309 8419 } 8310 - scan = loadoff(js, scan) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8420 + scan = next_prop(header); 8311 8421 } 8312 8422 { 8313 8423 const char *vn = &js->code[var_off]; ··· 8643 8753 jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 8644 8754 jsval_t func_obj = mkobj(js, 0); 8645 8755 if (is_err(func_obj)) return func_obj; 8646 - jsval_t code_key = js_mkstr(js, "__code", 6); 8647 - if (is_err(code_key)) return code_key; 8648 - jsval_t res2 = setprop(js, func_obj, code_key, str); 8649 - if (is_err(res2)) return res2; 8756 + set_slot(js, func_obj, SLOT_CODE, str); 8650 8757 jsval_t len_key = js_mkstr(js, "length", 6); 8651 8758 if (is_err(len_key)) return len_key; 8652 8759 jsval_t res_len = setprop(js, func_obj, len_key, tov(param_count)); ··· 8659 8766 jsval_t res3 = setprop(js, func_obj, name_key, name_val); 8660 8767 if (is_err(res3)) return res3; 8661 8768 if (exe) { 8662 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 8663 - if (is_err(scope_key)) return scope_key; 8664 - jsval_t res4 = setprop(js, func_obj, scope_key, js->scope); 8665 - if (is_err(res4)) return res4; 8769 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 8770 + if (flags & F_STRICT) { 8771 + set_slot(js, func_obj, SLOT_STRICT, js_mktrue()); 8772 + } 8666 8773 } 8667 8774 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 8668 8775 ··· 8709 8816 jsval_t str = js_mkstr(js, &js->code[pos], js->pos - pos); 8710 8817 jsval_t func_obj = mkobj(js, 0); 8711 8818 if (is_err(func_obj)) return func_obj; 8712 - jsval_t code_key = js_mkstr(js, "__code", 6); 8713 - if (is_err(code_key)) return code_key; 8714 - jsval_t res2 = setprop(js, func_obj, code_key, str); 8715 - if (is_err(res2)) return res2; 8716 - jsval_t async_key = js_mkstr(js, "__async", 7); 8717 - if (is_err(async_key)) return async_key; 8718 - jsval_t res_async = setprop(js, func_obj, async_key, js_mktrue()); 8719 - if (is_err(res_async)) return res_async; 8819 + set_slot(js, func_obj, SLOT_CODE, str); 8820 + set_slot(js, func_obj, SLOT_ASYNC, js_mktrue()); 8720 8821 jsval_t len_key = js_mkstr(js, "length", 6); 8721 8822 if (is_err(len_key)) return len_key; 8722 8823 jsval_t res_len = setprop(js, func_obj, len_key, tov(0)); ··· 8729 8830 jsval_t res3 = setprop(js, func_obj, name_key, name_val); 8730 8831 if (is_err(res3)) return res3; 8731 8832 if (exe) { 8732 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 8733 - if (is_err(scope_key)) return scope_key; 8734 - jsval_t res4 = setprop(js, func_obj, scope_key, js->scope); 8735 - if (is_err(res4)) return res4; 8833 + set_slot(js, func_obj, SLOT_SCOPE, js->scope); 8834 + if (flags & F_STRICT) { 8835 + set_slot(js, func_obj, SLOT_STRICT, js_mktrue()); 8836 + } 8736 8837 } 8737 8838 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 8738 8839 ··· 8841 8942 } 8842 8943 8843 8944 static bool for_in_should_skip_key(struct js *js, jsval_t obj, const char *key, jsoff_t klen) { 8844 - if (streq(key, klen, "__proto__", 9)) return true; 8945 + if (streq(key, klen, STR_PROTO, STR_PROTO_LEN)) return true; 8845 8946 8846 8947 jsoff_t obj_off = (jsoff_t)vdata(obj); 8847 8948 descriptor_entry_t *desc = lookup_descriptor(obj_off, key, klen); ··· 8855 8956 jsoff_t prop_off = loadoff(js, (jsoff_t) vdata(iter_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8856 8957 8857 8958 while (prop_off < js->brk && prop_off != 0) { 8959 + jsoff_t header = loadoff(js, prop_off); 8960 + if (is_slot_prop(header)) { prop_off = next_prop(header); continue; } 8961 + 8858 8962 jsoff_t koff = loadoff(js, prop_off + (jsoff_t) sizeof(prop_off)); 8859 8963 jsoff_t klen = offtolen(loadoff(js, koff)); 8860 8964 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 8872 8976 if (js->flags & F_RETURN) return v; 8873 8977 } 8874 8978 8875 - prop_off = loadoff(js, prop_off) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8979 + prop_off = next_prop(header); 8876 8980 } 8877 8981 8878 8982 return js_mkundef(); 8879 8983 } 8880 8984 8881 8985 static jsval_t for_of_iter_array(struct js *js, for_iter_ctx_t *ctx, jsval_t iterable) { 8882 - jsoff_t next_prop = loadoff(js, (jsoff_t) vdata(iterable)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8883 - jsoff_t length = 0, scan = next_prop; 8986 + jsoff_t next_prop_off = loadoff(js, (jsoff_t) vdata(iterable)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 8987 + jsoff_t length = 0, scan = next_prop_off; 8884 8988 8885 8989 while (scan < js->brk && scan != 0) { 8990 + jsoff_t header = loadoff(js, scan); 8991 + if (is_slot_prop(header)) { scan = next_prop(header); continue; } 8992 + 8886 8993 jsoff_t koff = loadoff(js, scan + (jsoff_t) sizeof(scan)); 8887 8994 jsoff_t klen = offtolen(loadoff(js, koff)); 8888 8995 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 8891 8998 if (vtype(val) == T_NUM) length = (jsoff_t) tod(val); 8892 8999 break; 8893 9000 } 8894 - scan = loadoff(js, scan) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 9001 + scan = next_prop(header); 8895 9002 } 8896 9003 8897 9004 for (jsoff_t i = 0; i < length; i++) { 8898 9005 char idx[16]; 8899 9006 snprintf(idx, sizeof(idx), "%u", (unsigned) i); 8900 9007 jsoff_t idxlen = (jsoff_t) strlen(idx); 8901 - jsoff_t prop = next_prop; 9008 + jsoff_t prop = next_prop_off; 8902 9009 jsval_t val = js_mkundef(); 8903 9010 8904 9011 while (prop < js->brk && prop != 0) { 9012 + jsoff_t header = loadoff(js, prop); 9013 + if (is_slot_prop(header)) { prop = next_prop(header); continue; } 9014 + 8905 9015 jsoff_t koff = loadoff(js, prop + (jsoff_t) sizeof(prop)); 8906 9016 jsoff_t klen = offtolen(loadoff(js, koff)); 8907 9017 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 8909 9019 val = loadval(js, prop + (jsoff_t) (sizeof(prop) + sizeof(koff))); 8910 9020 break; 8911 9021 } 8912 - prop = loadoff(js, prop) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 9022 + prop = next_prop(header); 8913 9023 } 8914 9024 8915 9025 jsval_t err = for_iter_bind_var(js, ctx, val); ··· 9137 9247 jsoff_t prop_off = loadoff(js, (jsoff_t) vdata(iter_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 9138 9248 9139 9249 while (prop_off < js->brk && prop_off != 0) { 9250 + jsoff_t header = loadoff(js, prop_off); 9251 + 9252 + if (is_slot_prop(header)) { 9253 + prop_off = next_prop(header); 9254 + continue; 9255 + } 9256 + 9140 9257 jsoff_t koff = loadoff(js, prop_off + (jsoff_t) sizeof(prop_off)); 9141 9258 jsoff_t klen = offtolen(loadoff(js, koff)); 9142 9259 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 9143 9260 9144 - bool should_skip = streq(key, klen, "__proto__", 9); 9261 + bool should_skip = streq(key, klen, STR_PROTO, STR_PROTO_LEN); 9145 9262 9146 9263 if (!should_skip && klen > 7 && key[0] == '_' && key[1] == '_' && 9147 9264 key[2] == 'd' && key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_') { ··· 10164 10281 utarray_push_back(global_scope_stack, &parent_scope_offset); 10165 10282 jsval_t with_scope = mkentity(js, 0 | T_OBJ, &parent_scope_offset, sizeof(parent_scope_offset)); 10166 10283 10167 - jsval_t with_marker = js_mkstr(js, "__with_object__", 15); 10168 - jsval_t with_ref = mkprop(js, with_scope, with_marker, with_obj, false); 10169 - if (is_err(with_ref)) return with_ref; 10284 + set_slot(js, with_scope, SLOT_WITH, with_obj); 10170 10285 10171 10286 jsval_t saved_scope = js->scope; 10172 10287 js->scope = with_scope; ··· 10453 10568 jsval_t method_obj = mkobj(js, 0); 10454 10569 if (is_err(method_obj)) return method_obj; 10455 10570 10456 - jsval_t mcode_key = js_mkstr(js, "__code", 6); 10457 - if (is_err(mcode_key)) return mcode_key; 10458 - jsval_t mres = setprop(js, method_obj, mcode_key, method_code); 10459 - if (is_err(mres)) return mres; 10571 + set_slot(js, method_obj, SLOT_CODE, method_code); 10460 10572 10461 10573 if (m->is_async) { 10462 - jsval_t async_key = js_mkstr(js, "__async", 7); 10463 - if (is_err(async_key)) return async_key; 10464 - jsval_t async_val = mkval(T_BOOL, 1); 10465 - jsval_t res_async = setprop(js, method_obj, async_key, async_val); 10466 - if (is_err(res_async)) return res_async; 10574 + set_slot(js, method_obj, SLOT_ASYNC, js_mktrue()); 10467 10575 } 10468 10576 10469 - jsval_t mscope_key = js_mkstr(js, "__scope", 7); 10470 - if (is_err(mscope_key)) return mscope_key; 10471 - jsval_t mscope_res = setprop(js, method_obj, mscope_key, func_scope); 10472 - if (is_err(mscope_res)) return mscope_res; 10577 + set_slot(js, method_obj, SLOT_SCOPE, func_scope); 10473 10578 10474 10579 jsval_t method_func = mkval(T_FUNC, (unsigned long) vdata(method_obj)); 10475 10580 ··· 10490 10595 10491 10596 jsval_t func_obj = mkobj(js, 0); 10492 10597 if (is_err(func_obj)) return func_obj; 10493 - 10494 - jsval_t code_key = js_mkstr(js, "__code", 6); 10495 - if (is_err(code_key)) return code_key; 10496 10598 10497 10599 jsval_t ctor_str; 10498 10600 if (constructor_params_start > 0 && constructor_body_start > 0) { ··· 10505 10607 } 10506 10608 if (is_err(ctor_str)) return ctor_str; 10507 10609 10508 - jsval_t res2 = setprop(js, func_obj, code_key, ctor_str); 10509 - if (is_err(res2)) return res2; 10610 + set_slot(js, func_obj, SLOT_CODE, ctor_str); 10510 10611 10511 10612 int instance_field_count = 0; 10512 10613 for (unsigned int i = 0; i < utarray_len(methods); i++) { ··· 10547 10648 jsval_t res_fields = setprop(js, func_obj, fields_key, fields_meta); 10548 10649 if (is_err(res_fields)) return res_fields; 10549 10650 10550 - jsval_t count_key = js_mkstr(js, "__field_count", 13); 10551 - if (is_err(count_key)) return count_key; 10552 - jsval_t res_count = setprop(js, func_obj, count_key, tov((double)instance_field_count)); 10553 - if (is_err(res_count)) return res_count; 10651 + set_slot(js, func_obj, SLOT_FIELD_COUNT, tov((double)instance_field_count)); 10554 10652 10555 10653 jsval_t src_key = js_mkstr(js, "__source", 8); 10556 10654 if (is_err(src_key)) return src_key; ··· 10560 10658 if (is_err(res_src)) return res_src; 10561 10659 } 10562 10660 10563 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 10564 - if (is_err(scope_key)) return scope_key; 10565 - jsval_t res3 = setprop(js, func_obj, scope_key, func_scope); 10566 - if (is_err(res3)) return res3; 10661 + set_slot(js, func_obj, SLOT_SCOPE, func_scope); 10567 10662 10568 10663 jsval_t name_key = js_mkstr(js, "name", 4); 10569 10664 if (is_err(name_key)) return name_key; ··· 10579 10674 10580 10675 jsval_t constructor = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 10581 10676 10677 + jsval_t ctor_key = js_mkstr(js, "constructor", 11); 10678 + if (is_err(ctor_key)) return ctor_key; 10679 + jsval_t ctor_res = setprop(js, proto, ctor_key, constructor); 10680 + if (is_err(ctor_res)) return ctor_res; 10681 + js_set_descriptor(js, proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 10682 + 10582 10683 if (class_name_len > 0) { 10583 10684 if (lkp(js, js->scope, class_name, class_name_len) > 0) { 10584 10685 return js_mkerr(js, "'%.*s' already declared", (int) class_name_len, class_name); ··· 10610 10711 jsval_t method_obj = mkobj(js, 0); 10611 10712 if (is_err(method_obj)) return method_obj; 10612 10713 10613 - jsval_t mcode_key = js_mkstr(js, "__code", 6); 10614 - if (is_err(mcode_key)) return mcode_key; 10615 - jsval_t mres = setprop(js, method_obj, mcode_key, method_code); 10616 - if (is_err(mres)) return mres; 10617 - 10618 - jsval_t mscope_key = js_mkstr(js, "__scope", 7); 10619 - if (is_err(mscope_key)) return mscope_key; 10620 - jsval_t mscope_res = setprop(js, method_obj, mscope_key, func_scope); 10621 - if (is_err(mscope_res)) return mscope_res; 10714 + set_slot(js, method_obj, SLOT_CODE, method_code); 10715 + set_slot(js, method_obj, SLOT_SCOPE, func_scope); 10622 10716 10623 10717 jsval_t method_func = mkval(T_FUNC, (unsigned long) vdata(method_obj)); 10624 10718 jsval_t set_res = setprop(js, func_obj, member_name, method_func); ··· 11128 11222 jsval_t func_obj = mkobj(js, 0); 11129 11223 if (is_err(func_obj)) return func_obj; 11130 11224 11131 - jsval_t code_key = js_mkstr(js, "__code", 6); 11132 - if (is_err(code_key)) return code_key; 11133 - 11134 - jsval_t res = setprop(js, func_obj, code_key, code_str); 11135 - if (is_err(res)) return res; 11136 - 11137 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 11138 - if (is_err(scope_key)) return scope_key; 11139 - 11140 - res = setprop(js, func_obj, scope_key, js_glob(js)); 11141 - if (is_err(res)) return res; 11225 + set_slot(js, func_obj, SLOT_CODE, code_str); 11226 + set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 11142 11227 11143 11228 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 11144 11229 ··· 11235 11320 jsval_t func_obj = mkobj(js, 0); 11236 11321 if (is_err(func_obj)) return func_obj; 11237 11322 11238 - jsval_t code_key = js_mkstr(js, "__code", 6); 11239 - if (is_err(code_key)) return code_key; 11240 - 11241 - jsval_t res = setprop(js, func_obj, code_key, code_str); 11242 - if (is_err(res)) return res; 11243 - 11244 - jsval_t scope_key = js_mkstr(js, "__scope", 7); 11245 - if (is_err(scope_key)) return scope_key; 11246 - 11247 - res = setprop(js, func_obj, scope_key, js_glob(js)); 11248 - if (is_err(res)) return res; 11323 + set_slot(js, func_obj, SLOT_CODE, code_str); 11324 + set_slot(js, func_obj, SLOT_SCOPE, js_glob(js)); 11249 11325 11250 11326 jsval_t func = mkval(T_FUNC, (unsigned long) vdata(func_obj)); 11251 11327 ··· 11371 11447 jsval_t bound_func = mkobj(js, 0); 11372 11448 if (is_err(bound_func)) return bound_func; 11373 11449 11374 - setprop(js, bound_func, js_mkstr(js, "__native_func", 13), func); 11375 - setprop(js, bound_func, js_mkstr(js, "__bound_this", 12), this_arg); 11450 + set_slot(js, bound_func, SLOT_CFUNC, func); 11451 + set_slot(js, bound_func, SLOT_BOUND_THIS, this_arg); 11376 11452 11377 11453 if (bound_argc > 0) { 11378 11454 jsval_t bound_arr = mkarr(js); ··· 11382 11458 setprop(js, bound_arr, js_mkstr(js, idx, strlen(idx)), bound_args[i]); 11383 11459 } 11384 11460 setprop(js, bound_arr, js_mkstr(js, "length", 6), tov((double) bound_argc)); 11385 - setprop(js, bound_func, js_mkstr(js, "__bound_args", 12), bound_arr); 11461 + set_slot(js, bound_func, SLOT_BOUND_ARGS, bound_arr); 11386 11462 } 11387 11463 11388 11464 jsval_t bound = mkval(T_FUNC, (unsigned long) vdata(bound_func)); ··· 11399 11475 jsval_t bound_func = mkobj(js, 0); 11400 11476 if (is_err(bound_func)) return bound_func; 11401 11477 11402 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 11403 - if (code_off != 0) { 11404 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 11405 - setprop(js, bound_func, js_mkstr(js, "__code", 6), code_val); 11478 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 11479 + if (vtype(code_val) == T_STR) { 11480 + set_slot(js, bound_func, SLOT_CODE, code_val); 11406 11481 } 11407 11482 11408 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 11409 - if (scope_off != 0) { 11410 - jsval_t scope_val = resolveprop(js, mkval(T_PROP, scope_off)); 11411 - setprop(js, bound_func, js_mkstr(js, "__scope", 7), scope_val); 11483 + jsval_t scope_slot = get_slot(js, func_obj, SLOT_SCOPE); 11484 + if (vtype(scope_slot) != T_UNDEF) { 11485 + set_slot(js, bound_func, SLOT_SCOPE, scope_slot); 11412 11486 } 11413 11487 11414 - jsoff_t async_off = lkp_interned(js, func_obj, INTERN_ASYNC, 7); 11415 - if (async_off != 0) { 11416 - jsval_t async_val = resolveprop(js, mkval(T_PROP, async_off)); 11417 - setprop(js, bound_func, js_mkstr(js, "__async", 7), async_val); 11488 + jsval_t async_slot = get_slot(js, func_obj, SLOT_ASYNC); 11489 + if (vtype(async_slot) == T_BOOL && vdata(async_slot) == 1) { 11490 + set_slot(js, bound_func, SLOT_ASYNC, js_mktrue()); 11418 11491 } 11419 11492 11420 11493 setprop(js, bound_func, js_mkstr(js, "__target_func", 13), func); 11421 - setprop(js, bound_func, js_mkstr(js, "__bound_this", 12), this_arg); 11494 + set_slot(js, bound_func, SLOT_BOUND_THIS, this_arg); 11422 11495 11423 11496 if (bound_argc > 0) { 11424 11497 jsval_t bound_arr = mkarr(js); ··· 11428 11501 setprop(js, bound_arr, js_mkstr(js, idx, strlen(idx)), bound_args[i]); 11429 11502 } 11430 11503 setprop(js, bound_arr, js_mkstr(js, "length", 6), tov((double) bound_argc)); 11431 - setprop(js, bound_func, js_mkstr(js, "__bound_args", 12), bound_arr); 11504 + set_slot(js, bound_func, SLOT_BOUND_ARGS, bound_arr); 11432 11505 } 11433 11506 11434 11507 setprop(js, bound_func, js_mkstr(js, "length", 6), tov((double) bound_length)); ··· 12784 12857 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12785 12858 12786 12859 while (next < js->brk && next != 0) { 12860 + jsoff_t header = loadoff(js, next); 12861 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 12862 + 12787 12863 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 12788 12864 jsoff_t klen = offtolen(loadoff(js, koff)); 12789 12865 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 12790 12866 12791 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12867 + next = next_prop(header); 12792 12868 if (is_internal_prop(key, klen)) continue; 12793 12869 12794 12870 bool should_include = true; ··· 12814 12890 12815 12891 next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12816 12892 while (next < js->brk && next != 0) { 12893 + jsoff_t header = loadoff(js, next); 12894 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 12895 + 12817 12896 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 12818 12897 jsoff_t klen = offtolen(loadoff(js, koff)); 12819 12898 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 12820 12899 12821 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12900 + next = next_prop(header); 12822 12901 12823 12902 if (klen > 7 && key[0] == '_' && key[1] == '_' && key[2] == 'd' && 12824 12903 key[3] == 'e' && key[4] == 's' && key[5] == 'c' && key[6] == '_') { ··· 12892 12971 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12893 12972 12894 12973 while (next < js->brk && next != 0) { 12974 + jsoff_t header = loadoff(js, next); 12975 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 12976 + 12895 12977 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 12896 12978 jsoff_t klen = offtolen(loadoff(js, koff)); 12897 12979 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 12898 12980 jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 12899 12981 12900 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12982 + next = next_prop(header); 12901 12983 if (is_internal_prop(key, klen)) continue; 12902 12984 12903 12985 bool should_include = true; ··· 12947 13029 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 12948 13030 12949 13031 while (next < js->brk && next != 0) { 13032 + jsoff_t header = loadoff(js, next); 13033 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13034 + 12950 13035 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 12951 13036 jsoff_t klen = offtolen(loadoff(js, koff)); 12952 13037 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 12953 13038 jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 12954 13039 12955 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13040 + next = next_prop(header); 12956 13041 12957 13042 if (is_internal_prop(key, klen)) continue; 12958 13043 ··· 13058 13143 jsoff_t next = loadoff(js, (jsoff_t) vdata(props)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13059 13144 13060 13145 while (next < js->brk && next != 0) { 13146 + jsoff_t header = loadoff(js, next); 13147 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13148 + 13061 13149 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13062 13150 jsoff_t klen = offtolen(loadoff(js, koff)); 13063 13151 const char *key = (char *) &js->mem[koff + sizeof(koff)]; ··· 13072 13160 } 13073 13161 } 13074 13162 13075 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13163 + next = next_prop(header); 13076 13164 } 13077 13165 } 13078 13166 ··· 13129 13217 jsoff_t prop_len, prop_off = vstr(js, prop, &prop_len); 13130 13218 const char *prop_str = (char *) &js->mem[prop_off]; 13131 13219 13132 - if (streq(prop_str, prop_len, "__proto__", 9)) { 13133 - return js_mkerr(js, "Cannot define __proto__ property"); 13220 + if (streq(prop_str, prop_len, STR_PROTO, STR_PROTO_LEN)) { 13221 + return js_mkerr(js, "Cannot define " STR_PROTO " property"); 13134 13222 } 13135 13223 13136 13224 bool has_value = false, has_get = false, has_set = false, has_writable = false; ··· 13264 13352 jsoff_t next = loadoff(js, (jsoff_t) vdata(props_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13265 13353 13266 13354 while (next < js->brk && next != 0) { 13355 + jsoff_t header = loadoff(js, next); 13356 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13357 + 13267 13358 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13268 13359 jsoff_t klen = offtolen(loadoff(js, koff)); 13269 13360 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 13270 13361 jsval_t descriptor = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 13271 13362 13272 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13363 + next = next_prop(header); 13273 13364 if (is_internal_prop(key, klen)) continue; 13274 13365 13275 13366 jsval_t prop_key = js_mkstr(js, key, klen); ··· 13308 13399 jsoff_t next = loadoff(js, (jsoff_t) vdata(src_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13309 13400 13310 13401 while (next < js->brk && next != 0) { 13402 + jsoff_t header = loadoff(js, next); 13403 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13404 + 13311 13405 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13312 13406 jsoff_t klen = offtolen(loadoff(js, koff)); 13313 13407 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 13314 13408 jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 13315 13409 13316 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13410 + next = next_prop(header); 13317 13411 if (is_internal_prop(key, klen)) continue; 13318 13412 13319 13413 bool should_copy = true; ··· 13345 13439 jsoff_t next = loadoff(js, (jsoff_t) vdata(as_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13346 13440 13347 13441 while (next < js->brk && next != 0) { 13442 + jsoff_t header = loadoff(js, next); 13443 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13444 + 13348 13445 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13349 13446 jsoff_t klen = offtolen(loadoff(js, koff)); 13350 13447 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 13351 13448 13352 13449 jsoff_t cur_prop = next; 13353 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13450 + next = next_prop(header); 13354 13451 if (is_internal_prop(key, klen)) continue; 13355 13452 13356 13453 jsoff_t head = (jsoff_t) vdata(as_obj); ··· 13409 13506 jsoff_t next = loadoff(js, (jsoff_t) vdata(as_obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13410 13507 13411 13508 while (next < js->brk && next != 0) { 13509 + jsoff_t header = loadoff(js, next); 13510 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13511 + 13412 13512 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13413 13513 jsoff_t klen = offtolen(loadoff(js, koff)); 13414 13514 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 13415 13515 13416 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13516 + next = next_prop(header); 13417 13517 13418 13518 if (is_internal_prop(key, klen)) continue; 13419 13519 ··· 13559 13659 jsoff_t next = loadoff(js, (jsoff_t) vdata(obj)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13560 13660 13561 13661 while (next < js->brk && next != 0) { 13662 + jsoff_t header = loadoff(js, next); 13663 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 13664 + 13562 13665 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 13563 13666 jsoff_t klen = offtolen(loadoff(js, koff)); 13564 13667 const char *key = (char *) &js->mem[koff + sizeof(koff)]; 13565 13668 13566 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 13669 + next = next_prop(header); 13567 13670 if (is_internal_prop(key, klen)) continue; 13568 13671 13569 13672 char idxstr[16]; ··· 17507 17610 17508 17611 static void trigger_handlers(struct js *js, jsval_t p) { 17509 17612 jsval_t wrapper_obj = mkobj(js, 0); 17510 - setprop_fast(js, wrapper_obj, "__native_func", 13, js_mkfun(builtin_trigger_handler_wrapper)); 17613 + set_slot(js, wrapper_obj, SLOT_CFUNC, js_mkfun(builtin_trigger_handler_wrapper)); 17511 17614 setprop_fast(js, wrapper_obj, "promise", 7, p); 17512 17615 jsval_t wrapper_fn = mkval(T_FUNC, vdata(wrapper_obj)); 17513 17616 queue_microtask(js, wrapper_fn); ··· 17569 17672 } 17570 17673 17571 17674 jsval_t res_obj = mkobj(js, 0); 17572 - setprop_fast(js, res_obj, "__native_func", 13, js_mkfun(builtin_resolve_internal)); 17675 + set_slot(js, res_obj, SLOT_CFUNC, js_mkfun(builtin_resolve_internal)); 17573 17676 setprop_fast(js, res_obj, "promise", 7, p); 17574 17677 jsval_t res_fn = mkval(T_FUNC, vdata(res_obj)); 17575 17678 17576 17679 jsval_t rej_obj = mkobj(js, 0); 17577 - setprop_fast(js, rej_obj, "__native_func", 13, js_mkfun(builtin_reject_internal)); 17680 + set_slot(js, rej_obj, SLOT_CFUNC, js_mkfun(builtin_reject_internal)); 17578 17681 setprop_fast(js, rej_obj, "promise", 7, p); 17579 17682 jsval_t rej_fn = mkval(T_FUNC, vdata(rej_obj)); 17580 17683 ··· 17620 17723 static jsval_t builtin_Promise(struct js *js, jsval_t *args, int nargs) { 17621 17724 jsval_t p = mkpromise(js); 17622 17725 jsval_t res_obj = mkobj(js, 0); 17623 - setprop(js, res_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_resolve_internal)); 17726 + set_slot(js, res_obj, SLOT_CFUNC, js_mkfun(builtin_resolve_internal)); 17624 17727 setprop(js, res_obj, js_mkstr(js, "promise", 7), p); 17625 17728 jsval_t res_fn = mkval(T_FUNC, vdata(res_obj)); 17626 17729 jsval_t rej_obj = mkobj(js, 0); 17627 - setprop(js, rej_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_reject_internal)); 17730 + set_slot(js, rej_obj, SLOT_CFUNC, js_mkfun(builtin_reject_internal)); 17628 17731 setprop(js, rej_obj, js_mkstr(js, "promise", 7), p); 17629 17732 jsval_t rej_fn = mkval(T_FUNC, vdata(rej_obj)); 17630 17733 if (nargs > 0) { ··· 17693 17796 17694 17797 static jsval_t resume_coroutine_wrapper(struct js *js, jsval_t *args, int nargs) { 17695 17798 jsval_t me = js->current_func; 17696 - jsval_t coro_val = js_get(js, me, "__coroutine"); 17799 + jsval_t coro_val = get_slot(js, me, SLOT_CORO); 17697 17800 if (vtype(coro_val) != T_NUM) return js_mkundef(); 17698 17801 17699 17802 coroutine_t *coro = (coroutine_t *)(uintptr_t)tod(coro_val); ··· 17710 17813 17711 17814 static jsval_t reject_coroutine_wrapper(struct js *js, jsval_t *args, int nargs) { 17712 17815 jsval_t me = js->current_func; 17713 - jsval_t coro_val = js_get(js, me, "__coroutine"); 17816 + jsval_t coro_val = get_slot(js, me, SLOT_CORO); 17714 17817 17715 17818 if (vtype(coro_val) != T_NUM) return js_mkundef(); 17716 17819 ··· 17800 17903 } 17801 17904 17802 17905 jsval_t resolve_obj = mkobj(js, 0); 17803 - setprop(js, resolve_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise_all_resolve_handler)); 17906 + set_slot(js, resolve_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_all_resolve_handler)); 17804 17907 setprop(js, resolve_obj, js_mkstr(js, "index", 5), tov((double)i)); 17805 17908 setprop(js, resolve_obj, js_mkstr(js, "tracker", 7), tracker); 17806 17909 jsval_t resolve_fn = mkval(T_FUNC, vdata(resolve_obj)); 17807 17910 17808 17911 jsval_t reject_obj = mkobj(js, 0); 17809 - setprop(js, reject_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise_all_reject_handler)); 17912 + set_slot(js, reject_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_all_reject_handler)); 17810 17913 setprop(js, reject_obj, js_mkstr(js, "tracker", 7), tracker); 17811 17914 jsval_t reject_fn = mkval(T_FUNC, vdata(reject_obj)); 17812 17915 ··· 17835 17938 jsval_t result_promise = mkpromise(js); 17836 17939 17837 17940 jsval_t resolve_obj = mkobj(js, 0); 17838 - setprop(js, resolve_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_resolve_internal)); 17941 + set_slot(js, resolve_obj, SLOT_CFUNC, js_mkfun(builtin_resolve_internal)); 17839 17942 setprop(js, resolve_obj, js_mkstr(js, "promise", 7), result_promise); 17840 17943 jsval_t resolve_fn = mkval(T_FUNC, vdata(resolve_obj)); 17841 17944 17842 17945 jsval_t reject_obj = mkobj(js, 0); 17843 - setprop(js, reject_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_reject_internal)); 17946 + set_slot(js, reject_obj, SLOT_CFUNC, js_mkfun(builtin_reject_internal)); 17844 17947 setprop(js, reject_obj, js_mkstr(js, "promise", 7), result_promise); 17845 17948 jsval_t reject_fn = mkval(T_FUNC, vdata(reject_obj)); 17846 17949 ··· 17967 18070 } 17968 18071 17969 18072 jsval_t resolve_obj = mkobj(js, 0); 17970 - setprop(js, resolve_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise_any_resolve_handler)); 18073 + set_slot(js, resolve_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_any_resolve_handler)); 17971 18074 setprop(js, resolve_obj, js_mkstr(js, "tracker", 7), tracker); 17972 18075 17973 18076 jsval_t reject_obj = mkobj(js, 0); 17974 - setprop(js, reject_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise_any_reject_handler)); 18077 + set_slot(js, reject_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_any_reject_handler)); 17975 18078 setprop(js, reject_obj, js_mkstr(js, "index", 5), tov((double)i)); 17976 18079 setprop(js, reject_obj, js_mkstr(js, "tracker", 7), tracker); 17977 18080 ··· 19659 19762 if (is_err(proxy)) return proxy; 19660 19763 19661 19764 jsval_t revoke_obj = mkobj(js, 0); 19662 - setprop(js, revoke_obj, js_mkstr(js, "__native_func", 13), js_mkfun(proxy_revoke_fn)); 19765 + set_slot(js, revoke_obj, SLOT_CFUNC, js_mkfun(proxy_revoke_fn)); 19663 19766 setprop(js, revoke_obj, js_mkstr(js, "__proxy_ref__", 13), proxy); 19664 19767 19665 19768 jsval_t revoke_func = mkval(T_FUNC, vdata(revoke_obj)); ··· 20082 20185 20083 20186 jsval_t obj_func_obj = mkobj(js, 0); 20084 20187 set_proto(js, obj_func_obj, function_proto); 20085 - setprop(js, obj_func_obj, js_mkstr(js, "__code", 6), js_mkstr(js, "__builtin_Object", 16)); 20188 + set_slot(js, obj_func_obj, SLOT_CODE, js_mkstr(js, "__builtin_Object", 16)); 20086 20189 setprop(js, obj_func_obj, js_mkstr(js, "keys", 4), js_mkfun(builtin_object_keys)); 20087 20190 setprop(js, obj_func_obj, js_mkstr(js, "values", 6), js_mkfun(builtin_object_values)); 20088 20191 setprop(js, obj_func_obj, js_mkstr(js, "entries", 7), js_mkfun(builtin_object_entries)); ··· 20107 20210 20108 20211 jsval_t func_ctor_obj = mkobj(js, 0); 20109 20212 set_proto(js, func_ctor_obj, function_proto); 20110 - setprop(js, func_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Function)); 20213 + set_slot(js, func_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Function)); 20111 20214 setprop_nonconfigurable(js, func_ctor_obj, "prototype", 9, function_proto); 20112 20215 setprop(js, func_ctor_obj, js_mkstr(js, "length", 6), tov(1.0)); 20113 20216 js_set_descriptor(js, func_ctor_obj, "length", 6, JS_DESC_C); ··· 20115 20218 20116 20219 jsval_t str_ctor_obj = mkobj(js, 0); 20117 20220 set_proto(js, str_ctor_obj, function_proto); 20118 - setprop(js, str_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_String)); 20221 + set_slot(js, str_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_String)); 20119 20222 setprop_nonconfigurable(js, str_ctor_obj, "prototype", 9, string_proto); 20120 20223 setprop(js, str_ctor_obj, js_mkstr(js, "fromCharCode", 12), js_mkfun(builtin_string_fromCharCode)); 20121 20224 setprop(js, str_ctor_obj, js_mkstr(js, "fromCodePoint", 13), js_mkfun(builtin_string_fromCodePoint)); ··· 20124 20227 jsval_t number_ctor_obj = mkobj(js, 0); 20125 20228 set_proto(js, number_ctor_obj, function_proto); 20126 20229 20127 - setprop(js, number_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Number)); 20230 + set_slot(js, number_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Number)); 20128 20231 setprop(js, number_ctor_obj, js_mkstr(js, "isNaN", 5), js_mkfun(builtin_Number_isNaN)); 20129 20232 setprop(js, number_ctor_obj, js_mkstr(js, "isFinite", 8), js_mkfun(builtin_Number_isFinite)); 20130 20233 setprop(js, number_ctor_obj, js_mkstr(js, "isInteger", 9), js_mkfun(builtin_Number_isInteger)); ··· 20144 20247 20145 20248 jsval_t bool_ctor_obj = mkobj(js, 0); 20146 20249 set_proto(js, bool_ctor_obj, function_proto); 20147 - setprop(js, bool_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Boolean)); 20250 + set_slot(js, bool_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Boolean)); 20148 20251 setprop_nonconfigurable(js, bool_ctor_obj, "prototype", 9, boolean_proto); 20149 20252 setprop(js, glob, js_mkstr(js, "Boolean", 7), mkval(T_FUNC, vdata(bool_ctor_obj))); 20150 20253 20151 20254 jsval_t arr_ctor_obj = mkobj(js, 0); 20152 20255 set_proto(js, arr_ctor_obj, function_proto); 20153 - setprop(js, arr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Array)); 20256 + set_slot(js, arr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Array)); 20154 20257 setprop_nonconfigurable(js, arr_ctor_obj, "prototype", 9, array_proto); 20155 20258 setprop(js, arr_ctor_obj, js_mkstr(js, "isArray", 7), js_mkfun(builtin_Array_isArray)); 20156 20259 setprop(js, arr_ctor_obj, js_mkstr(js, "from", 4), js_mkfun(builtin_Array_from)); ··· 20161 20264 20162 20265 jsval_t map_ctor_obj = mkobj(js, 0); 20163 20266 set_proto(js, map_ctor_obj, function_proto); 20164 - setprop(js, map_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Map)); 20267 + set_slot(js, map_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Map)); 20165 20268 setprop_nonconfigurable(js, map_ctor_obj, "prototype", 9, map_proto); 20166 20269 setprop(js, glob, js_mkstr(js, "Map", 3), mkval(T_FUNC, vdata(map_ctor_obj))); 20167 20270 20168 20271 jsval_t set_ctor_obj = mkobj(js, 0); 20169 20272 set_proto(js, set_ctor_obj, function_proto); 20170 - setprop(js, set_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Set)); 20273 + set_slot(js, set_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Set)); 20171 20274 setprop_nonconfigurable(js, set_ctor_obj, "prototype", 9, set_proto_obj); 20172 20275 setprop(js, glob, js_mkstr(js, "Set", 3), mkval(T_FUNC, vdata(set_ctor_obj))); 20173 20276 20174 20277 jsval_t weakmap_ctor_obj = mkobj(js, 0); 20175 20278 set_proto(js, weakmap_ctor_obj, function_proto); 20176 - setprop(js, weakmap_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_WeakMap)); 20279 + set_slot(js, weakmap_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_WeakMap)); 20177 20280 setprop_nonconfigurable(js, weakmap_ctor_obj, "prototype", 9, weakmap_proto); 20178 20281 setprop(js, glob, js_mkstr(js, "WeakMap", 7), mkval(T_FUNC, vdata(weakmap_ctor_obj))); 20179 20282 20180 20283 jsval_t weakset_ctor_obj = mkobj(js, 0); 20181 20284 set_proto(js, weakset_ctor_obj, function_proto); 20182 - setprop(js, weakset_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_WeakSet)); 20285 + set_slot(js, weakset_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_WeakSet)); 20183 20286 setprop_nonconfigurable(js, weakset_ctor_obj, "prototype", 9, weakset_proto); 20184 20287 setprop(js, glob, js_mkstr(js, "WeakSet", 7), mkval(T_FUNC, vdata(weakset_ctor_obj))); 20185 20288 20186 20289 jsval_t proxy_ctor_obj = mkobj(js, 0); 20187 20290 set_proto(js, proxy_ctor_obj, function_proto); 20188 - setprop(js, proxy_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Proxy)); 20291 + set_slot(js, proxy_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Proxy)); 20189 20292 setprop(js, proxy_ctor_obj, js_mkstr(js, "revocable", 9), js_mkfun(builtin_Proxy_revocable)); 20190 20293 setprop(js, glob, js_mkstr(js, "Proxy", 5), mkval(T_FUNC, vdata(proxy_ctor_obj))); 20191 20294 20192 20295 jsval_t err_ctor_obj = mkobj(js, 0); 20193 20296 set_proto(js, err_ctor_obj, function_proto); 20194 - setprop(js, err_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Error)); 20297 + set_slot(js, err_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Error)); 20195 20298 setprop_nonconfigurable(js, err_ctor_obj, "prototype", 9, error_proto); 20196 20299 setprop(js, glob, js_mkstr(js, "Error", 5), mkval(T_FUNC, vdata(err_ctor_obj))); 20197 20300 20198 20301 jsval_t evalerr_ctor_obj = mkobj(js, 0); 20199 20302 set_proto(js, evalerr_ctor_obj, function_proto); 20200 - setprop(js, evalerr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_EvalError)); 20303 + set_slot(js, evalerr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_EvalError)); 20201 20304 setprop_nonconfigurable(js, evalerr_ctor_obj, "prototype", 9, evalerror_proto); 20202 20305 setprop(js, glob, js_mkstr(js, "EvalError", 9), mkval(T_FUNC, vdata(evalerr_ctor_obj))); 20203 20306 20204 20307 jsval_t rangeerr_ctor_obj = mkobj(js, 0); 20205 20308 set_proto(js, rangeerr_ctor_obj, function_proto); 20206 - setprop(js, rangeerr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_RangeError)); 20309 + set_slot(js, rangeerr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_RangeError)); 20207 20310 setprop_nonconfigurable(js, rangeerr_ctor_obj, "prototype", 9, rangeerror_proto); 20208 20311 setprop(js, glob, js_mkstr(js, "RangeError", 10), mkval(T_FUNC, vdata(rangeerr_ctor_obj))); 20209 20312 20210 20313 jsval_t referr_ctor_obj = mkobj(js, 0); 20211 20314 set_proto(js, referr_ctor_obj, function_proto); 20212 - setprop(js, referr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_ReferenceError)); 20315 + set_slot(js, referr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_ReferenceError)); 20213 20316 setprop_nonconfigurable(js, referr_ctor_obj, "prototype", 9, referenceerror_proto); 20214 20317 setprop(js, glob, js_mkstr(js, "ReferenceError", 14), mkval(T_FUNC, vdata(referr_ctor_obj))); 20215 20318 20216 20319 jsval_t syntaxerr_ctor_obj = mkobj(js, 0); 20217 20320 set_proto(js, syntaxerr_ctor_obj, function_proto); 20218 - setprop(js, syntaxerr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_SyntaxError)); 20321 + set_slot(js, syntaxerr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_SyntaxError)); 20219 20322 setprop_nonconfigurable(js, syntaxerr_ctor_obj, "prototype", 9, syntaxerror_proto); 20220 20323 setprop(js, glob, js_mkstr(js, "SyntaxError", 11), mkval(T_FUNC, vdata(syntaxerr_ctor_obj))); 20221 20324 20222 20325 jsval_t typeerr_ctor_obj = mkobj(js, 0); 20223 20326 set_proto(js, typeerr_ctor_obj, function_proto); 20224 - setprop(js, typeerr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_TypeError)); 20327 + set_slot(js, typeerr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_TypeError)); 20225 20328 setprop_nonconfigurable(js, typeerr_ctor_obj, "prototype", 9, typeerror_proto); 20226 20329 setprop(js, glob, js_mkstr(js, "TypeError", 9), mkval(T_FUNC, vdata(typeerr_ctor_obj))); 20227 20330 20228 20331 jsval_t urierr_ctor_obj = mkobj(js, 0); 20229 20332 set_proto(js, urierr_ctor_obj, function_proto); 20230 - setprop(js, urierr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_URIError)); 20333 + set_slot(js, urierr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_URIError)); 20231 20334 setprop_nonconfigurable(js, urierr_ctor_obj, "prototype", 9, urierror_proto); 20232 20335 setprop(js, glob, js_mkstr(js, "URIError", 8), mkval(T_FUNC, vdata(urierr_ctor_obj))); 20233 20336 20234 20337 jsval_t internerr_ctor_obj = mkobj(js, 0); 20235 20338 set_proto(js, internerr_ctor_obj, function_proto); 20236 - setprop(js, internerr_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_InternalError)); 20339 + set_slot(js, internerr_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_InternalError)); 20237 20340 setprop_nonconfigurable(js, internerr_ctor_obj, "prototype", 9, internalerror_proto); 20238 20341 setprop(js, glob, js_mkstr(js, "InternalError", 13), mkval(T_FUNC, vdata(internerr_ctor_obj))); 20239 20342 20240 20343 jsval_t regex_ctor_obj = mkobj(js, 0); 20241 20344 set_proto(js, regex_ctor_obj, function_proto); 20242 - setprop(js, regex_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_RegExp)); 20345 + set_slot(js, regex_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_RegExp)); 20243 20346 setprop_nonconfigurable(js, regex_ctor_obj, "prototype", 9, regexp_proto); 20244 20347 setprop(js, glob, js_mkstr(js, "RegExp", 6), mkval(T_FUNC, vdata(regex_ctor_obj))); 20245 20348 20246 20349 jsval_t date_ctor_obj = mkobj(js, 0); 20247 20350 set_proto(js, date_ctor_obj, function_proto); 20248 - setprop(js, date_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Date)); 20351 + set_slot(js, date_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Date)); 20249 20352 setprop(js, date_ctor_obj, js_mkstr(js, "now", 3), js_mkfun(builtin_Date_now)); 20250 20353 setprop(js, date_ctor_obj, js_mkstr(js, "UTC", 3), js_mkfun(builtin_Date_UTC)); 20251 20354 setprop_nonconfigurable(js, date_ctor_obj, "prototype", 9, date_proto); ··· 20253 20356 20254 20357 jsval_t p_ctor_obj = mkobj(js, 0); 20255 20358 set_proto(js, p_ctor_obj, function_proto); 20256 - setprop(js, p_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Promise)); 20359 + set_slot(js, p_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Promise)); 20257 20360 setprop(js, p_ctor_obj, js_mkstr(js, "resolve", 7), js_mkfun(builtin_Promise_resolve)); 20258 20361 setprop(js, p_ctor_obj, js_mkstr(js, "reject", 6), js_mkfun(builtin_Promise_reject)); 20259 20362 setprop(js, p_ctor_obj, js_mkstr(js, "try", 3), js_mkfun(builtin_Promise_try)); ··· 20265 20368 20266 20369 jsval_t bigint_ctor_obj = mkobj(js, 0); 20267 20370 set_proto(js, bigint_ctor_obj, function_proto); 20268 - setprop(js, bigint_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_BigInt)); 20371 + set_slot(js, bigint_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_BigInt)); 20269 20372 setprop(js, bigint_ctor_obj, js_mkstr(js, "asIntN", 6), js_mkfun(builtin_BigInt_asIntN)); 20270 20373 setprop(js, bigint_ctor_obj, js_mkstr(js, "asUintN", 7), js_mkfun(builtin_BigInt_asUintN)); 20271 20374 setprop_nonconfigurable(js, bigint_ctor_obj, "prototype", 9, bigint_proto); ··· 20332 20435 jsval_t import_obj = mkobj(js, 0); 20333 20436 set_proto(js, import_obj, function_proto); 20334 20437 20335 - setprop(js, import_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_import)); 20438 + set_slot(js, import_obj, SLOT_CFUNC, js_mkfun(builtin_import)); 20336 20439 setprop(js, glob, js_mkstr(js, "import", 6), mkval(T_FUNC, vdata(import_obj))); 20337 20440 setprop(js, glob, js_mkstr(js, "__esm_module_scope", 18), js_mkundef()); 20338 20441 ··· 20529 20632 if (vtype(dst) != T_OBJ || vtype(src) != T_OBJ) return; 20530 20633 jsoff_t next = loadoff(js, (jsoff_t) vdata(src)) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 20531 20634 while (next < js->brk && next != 0) { 20635 + jsoff_t header = loadoff(js, next); 20636 + if (is_slot_prop(header)) { next = next_prop(header); continue; } 20637 + 20532 20638 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); 20533 20639 jsval_t val = loadval(js, next + (jsoff_t) (sizeof(next) + sizeof(koff))); 20534 20640 jsoff_t klen = offtolen(loadoff(js, koff)); 20535 20641 20536 20642 char *key = (char *) &js->mem[koff + sizeof(koff)]; 20537 20643 setprop(js, dst, js_mkstr(js, key, klen), val); 20538 - next = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 20644 + next = next_prop(header); 20539 20645 } 20540 20646 } 20541 20647 ··· 20646 20752 return res; 20647 20753 } else if (vtype(func) == T_FUNC) { 20648 20754 jsval_t func_obj = mkval(T_OBJ, vdata(func)); 20649 - jsoff_t native_off = lkp_interned(js, func_obj, INTERN_NATIVE_FUNC, 13); 20650 - if (native_off != 0) { 20651 - jsval_t native_val = resolveprop(js, mkval(T_PROP, native_off)); 20652 - if (vtype(native_val) == T_CFUNC) { 20653 - jsval_t saved_func = js->current_func; 20654 - jsval_t saved_this = js->this_val; 20655 - js->current_func = func; 20656 - if (use_bound_this) js->this_val = bound_this; 20657 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(native_val); 20658 - jsval_t res = fn(js, args, nargs); 20659 - js->current_func = saved_func; 20660 - js->this_val = saved_this; 20661 - return res; 20662 - } 20755 + jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 20756 + if (vtype(cfunc_slot) == T_CFUNC) { 20757 + jsval_t saved_func = js->current_func; 20758 + jsval_t saved_this = js->this_val; 20759 + js->current_func = func; 20760 + if (use_bound_this) js->this_val = bound_this; 20761 + jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot); 20762 + jsval_t res = fn(js, args, nargs); 20763 + js->current_func = saved_func; 20764 + js->this_val = saved_this; 20765 + return res; 20663 20766 } 20664 - jsoff_t code_off = lkp_interned(js, func_obj, INTERN_CODE, 6); 20665 - 20666 - if (code_off == 0) return js_mkerr(js, "function has no code"); 20667 - jsval_t code_val = resolveprop(js, mkval(T_PROP, code_off)); 20668 - if (vtype(code_val) != T_STR) return js_mkerr(js, "function code not string"); 20767 + jsval_t code_val = get_slot(js, func_obj, SLOT_CODE); 20768 + if (vtype(code_val) != T_STR) return js_mkerr(js, "function has no code"); 20669 20769 jsoff_t fnlen, fnoff = vstr(js, code_val, &fnlen); 20670 20770 const char *fn = (const char *) (&js->mem[fnoff]); 20671 20771 20672 - jsoff_t async_off = lkp_interned(js, func_obj, INTERN_ASYNC, 7); 20673 - bool is_async = false; 20674 - if (async_off != 0) { 20675 - jsval_t async_val = resolveprop(js, mkval(T_PROP, async_off)); 20676 - is_async = vtype(async_val) == T_BOOL && vdata(async_val) == 1; 20677 - } 20772 + jsval_t async_slot = get_slot(js, func_obj, SLOT_ASYNC); 20773 + bool is_async = vtype(async_slot) == T_BOOL && vdata(async_slot) == 1; 20678 20774 20679 20775 if (is_async) { 20680 - jsval_t closure_scope = js_mkundef(); 20681 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 20682 - if (scope_off != 0) { 20683 - closure_scope = resolveprop(js, mkval(T_PROP, scope_off)); 20684 - } 20776 + jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 20685 20777 return start_async_in_coroutine(js, fn, fnlen, closure_scope, args, nargs); 20686 20778 } 20687 20779 20688 20780 jsval_t saved_scope = js->scope; 20689 - jsoff_t scope_off = lkp_interned(js, func_obj, INTERN_SCOPE, 7); 20690 - if (scope_off != 0) { 20691 - jsval_t closure_scope = resolveprop(js, mkval(T_PROP, scope_off)); 20692 - if (vtype(closure_scope) == T_OBJ) { 20693 - js->scope = closure_scope; 20694 - } 20781 + jsval_t closure_scope = get_slot(js, func_obj, SLOT_SCOPE); 20782 + if (vtype(closure_scope) == T_OBJ) { 20783 + js->scope = closure_scope; 20695 20784 } 20696 20785 20697 20786 uint8_t saved_flags = js->flags; ··· 20795 20884 struct js *js = (struct js *)iter->js_internal; 20796 20885 jsoff_t next = (jsoff_t)(uintptr_t)iter->current; 20797 20886 20887 + while (next < js->brk && next != 0) { 20888 + jsoff_t header = loadoff(js, next); 20889 + if (!is_slot_prop(header)) break; 20890 + next = next_prop(header); 20891 + } 20892 + 20798 20893 if (next >= js->brk || next == 0) return false; 20799 20894 20800 20895 jsoff_t koff = loadoff(js, next + (jsoff_t) sizeof(next)); ··· 20808 20903 20809 20904 if (value) *value = val; 20810 20905 20811 - iter->current = (void *)(uintptr_t)(loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK)); 20906 + jsoff_t next_off = loadoff(js, next) & ~(3U | CONSTMASK | ARRMASK | SLOTMASK); 20907 + while (next_off < js->brk && next_off != 0) { 20908 + jsoff_t header = loadoff(js, next_off); 20909 + if (!is_slot_prop(header)) break; 20910 + next_off = next_prop(header); 20911 + } 20912 + iter->current = (void *)(uintptr_t)next_off; 20812 20913 return true; 20813 20914 } 20814 20915 ··· 20822 20923 jsval_t js_mkpromise(struct js *js) { return mkpromise(js); } 20823 20924 void js_resolve_promise(struct js *js, jsval_t promise, jsval_t value) { resolve_promise(js, promise, value); } 20824 20925 void js_reject_promise(struct js *js, jsval_t promise, jsval_t value) { reject_promise(js, promise, value); } 20926 + 20927 + bool js_is_slot_prop(jsoff_t header) { return is_slot_prop(header); } 20928 + jsoff_t js_next_prop(jsoff_t header) { return next_prop(header); } 20929 + jsoff_t js_loadoff(struct js *js, jsoff_t off) { return loadoff(js, off); } 20825 20930 20826 20931 #ifdef JS_DUMP 20827 20932 void js_dump(struct js *js) { ··· 20979 21084 } 20980 21085 } 20981 21086 } 21087 + 21088 + jsval_t js_get_slot(struct js *js, jsval_t obj, internal_slot_t slot) { return get_slot(js, obj, slot); } 21089 + void js_set_slot(struct js *js, jsval_t obj, internal_slot_t slot, jsval_t value) { set_slot(js, obj, slot, value); }
+2 -2
src/modules/buffer.c
··· 870 870 jsval_t arraybuffer_ctor_obj = js_mkobj(js); 871 871 jsval_t arraybuffer_proto = js_mkobj(js); 872 872 js_set(js, arraybuffer_proto, "slice", js_mkfun(js_arraybuffer_slice)); 873 - js_setprop(js, arraybuffer_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(js_arraybuffer_constructor)); 873 + js_set_slot(js, arraybuffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_arraybuffer_constructor)); 874 874 js_setprop(js, arraybuffer_ctor_obj, js_mkstr(js, "prototype", 9), arraybuffer_proto); 875 875 js_set(js, glob, "ArrayBuffer", js_obj_to_func(arraybuffer_ctor_obj)); 876 876 ··· 881 881 js_set(js, name##_proto, "slice", js_mkfun(js_typedarray_slice)); \ 882 882 js_set(js, name##_proto, "subarray", js_mkfun(js_typedarray_subarray)); \ 883 883 js_set(js, name##_proto, "fill", js_mkfun(js_typedarray_fill)); \ 884 - js_setprop(js, name##_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(js_##name##_constructor)); \ 884 + js_set_slot(js, name##_ctor_obj, SLOT_CFUNC, js_mkfun(js_##name##_constructor)); \ 885 885 js_setprop(js, name##_ctor_obj, js_mkstr(js, "prototype", 9), name##_proto); \ 886 886 js_set(js, glob, #name, js_obj_to_func(name##_ctor_obj)); \ 887 887 } while(0)
+2 -2
src/modules/fetch.c
··· 65 65 const char *json_code = "(){return JSON.parse(this.body)}"; 66 66 jsval_t json_str = js_mkstr(js, json_code, strlen(json_code)); 67 67 jsval_t json_obj = js_mkobj(js); 68 - js_set(js, json_obj, "__code", json_str); 68 + js_set_slot(js, json_obj, SLOT_CODE, json_str); 69 69 js_set(js, response_obj, "json", js_obj_to_func(json_obj)); 70 70 71 71 return response_obj; ··· 294 294 jsval_t promise = js_mkpromise(js); 295 295 jsval_t wrapper_obj = js_mkobj(js); 296 296 297 - js_set(js, wrapper_obj, "__native_func", js_mkfun(do_fetch_microtask)); 297 + js_set_slot(js, wrapper_obj, SLOT_CFUNC, js_mkfun(do_fetch_microtask)); 298 298 js_set(js, wrapper_obj, "url", url_val); 299 299 js_set(js, wrapper_obj, "options", options_val); 300 300 js_set(js, wrapper_obj, "promise", promise);
+1 -1
src/modules/json.c
··· 88 88 if (key_len >= 2 && key[0] == '_' && key[1] == '_') return 1; 89 89 if (js_type(value) != JS_OBJ) return 0; 90 90 91 - jsval_t code = js_get(js, value, "__code"); 91 + jsval_t code = js_get_slot(js, value, SLOT_CODE); 92 92 return js_type(code) == JS_STR; 93 93 } 94 94
+1 -1
src/modules/reflect.c
··· 100 100 jsval_t value; 101 101 102 102 while (js_prop_iter_next(&iter, &key, &key_len, &value) && count < 256) { 103 - if (key_len >= 9 && memcmp(key, "__proto__", 9) == 0) continue; 103 + if (key_len >= 9 && memcmp(key, STR_PROTO, STR_PROTO_LEN) == 0) continue; 104 104 if (key_len >= 2 && key[0] == '_' && key[1] == '_') continue; 105 105 106 106 temp_keys[count++] = js_mkstr(js, key, key_len);
+1 -1
src/modules/symbol.c
··· 157 157 snprintf(g_toStringTag_sym_key, sizeof(g_toStringTag_sym_key), "__sym_%llu__", (unsigned long long)js_sym_id(g_toStringTag_sym)); 158 158 159 159 jsval_t symbol_ctor = js_mkobj(js); 160 - js_set(js, symbol_ctor, "__native_func", js_mkfun(builtin_Symbol)); 160 + js_set_slot(js, symbol_ctor, SLOT_CFUNC, js_mkfun(builtin_Symbol)); 161 161 js_setprop(js, symbol_ctor, js_mkstr(js, "for", 3), js_mkfun(builtin_Symbol_for)); 162 162 js_set(js, symbol_ctor, "keyFor", js_mkfun(builtin_Symbol_keyFor)); 163 163