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.

implement proxy support for array methods and instanceof operator

+278 -138
+4 -4
include/modules/symbol.h
··· 2 2 #define SYMBOL_H 3 3 4 4 #include <stddef.h> 5 + #include "types.h" 5 6 6 7 void init_symbol_module(void); 8 + bool is_symbol_key(const char *key, size_t key_len); 7 9 8 10 const char *get_iterator_sym_key(void); 9 11 const char *get_asyncIterator_sym_key(void); ··· 12 14 const char *get_toPrimitive_sym_key(void); 13 15 const char *get_hasInstance_sym_key(void); 14 16 15 - const char *get_symbol_description_from_key( 16 - const char *sym_key, 17 - size_t key_len 18 - ); 17 + jsval_t get_wellknown_sym_by_key(const char *key, size_t key_len); 18 + const char *get_symbol_description_from_key(const char *sym_key, size_t key_len); 19 19 20 20 #endif
+252 -133
src/ant.c
··· 708 708 709 709 static bool is_digit(int c); 710 710 static bool is_proxy(struct js *js, jsval_t obj); 711 + static jsval_t proxy_read_target(struct js *js, jsval_t obj); 712 + static jsoff_t proxy_aware_length(struct js *js, jsval_t obj); 713 + static jsval_t proxy_aware_get_elem(struct js *js, jsval_t obj, const char *key, size_t key_len); 711 714 static bool bigint_is_zero(struct js *js, jsval_t v); 712 715 713 716 static bool streq(const char *buf, size_t len, const char *p, size_t n); ··· 15862 15865 jsoff_t klen = offtolen(loadoff(js, koff)); 15863 15866 const char *key = (char *)&js->mem[koff + sizeof(koff)]; 15864 15867 15865 - if (klen >= 9 && memcmp(key, "__sym_", 6) == 0 && memcmp(key + klen - 2, "__", 2) == 0) { 15868 + if (is_symbol_key(key, klen)) { 15866 15869 uint64_t sym_id = 0; 15867 15870 for (const char *p = key + 6; *p >= '0' && *p <= '9' && sym_id <= PROPREF_PAYLOAD / 10; p++) 15868 15871 sym_id = sym_id * 10 + (uint64_t)(*p - '0'); ··· 16149 16152 16150 16153 static jsval_t builtin_array_pop(struct js *js, jsval_t *args, int nargs) { 16151 16154 jsval_t arr = js->this_val; 16152 - 16155 + 16153 16156 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 16154 16157 return js_mkerr(js, "pop called on non-array"); 16155 16158 } 16156 - 16159 + 16160 + if (is_proxy(js, arr)) { 16161 + jsoff_t len = proxy_aware_length(js, arr); 16162 + if (len == 0) { 16163 + jsval_t len_key = js_mkstr(js, "length", 6); 16164 + js_setprop(js, arr, len_key, tov(0.0)); 16165 + return js_mkundef(); 16166 + } 16167 + len--; 16168 + char idxstr[16]; 16169 + size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); 16170 + jsval_t result = proxy_aware_get_elem(js, arr, idxstr, idxlen); 16171 + jsval_t len_key = js_mkstr(js, "length", 6); 16172 + js_setprop(js, arr, len_key, tov((double) len)); 16173 + js->needs_gc = true; 16174 + return result; 16175 + } 16176 + 16157 16177 jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16158 16178 jsoff_t len = 0; 16159 - 16179 + 16160 16180 if (off != 0) { 16161 16181 jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16162 16182 if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16163 16183 } 16164 - 16184 + 16165 16185 if (len == 0) return js_mkundef(); 16166 16186 len--; char idxstr[16]; 16167 16187 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)len); ··· 16169 16189 jsoff_t arr_off = (jsoff_t)vdata(arr); 16170 16190 jsoff_t tail = loadoff(js, arr_off + sizeof(jsoff_t) * 2); 16171 16191 jsoff_t elem_off = 0; 16172 - 16192 + 16173 16193 if (tail != 0 && tail < js->brk) { 16174 16194 jsoff_t tail_hdr = loadoff(js, tail); 16175 16195 if ((tail_hdr & SLOTMASK) == 0) { ··· 16179 16199 if (tail_klen == idxlen && memcmp(tail_key, idxstr, idxlen) == 0) elem_off = tail; 16180 16200 } 16181 16201 } 16182 - 16202 + 16183 16203 if (elem_off == 0) elem_off = lkp(js, arr, idxstr, idxlen); 16184 16204 jsval_t result = js_mkundef(); 16185 16205 if (elem_off != 0) result = resolveprop(js, mkval(T_PROP, elem_off)); 16186 16206 16187 - if (is_proxy(js, arr)) { 16188 - jsval_t len_key = js_mkstr(js, "length", 6); 16189 - js_setprop(js, arr, len_key, tov((double) len)); 16190 - } else if (off != 0) { 16207 + if (off != 0) { 16191 16208 saveval(js, off + sizeof(jsoff_t) * 2, tov((double) len)); 16192 16209 } else { 16193 16210 jsval_t len_key = js_mkstr(js, "length", 6); 16194 16211 js_setprop(js, arr, len_key, tov((double) len)); 16195 16212 } 16196 - 16213 + 16197 16214 js->needs_gc = true; 16198 16215 return result; 16199 16216 } ··· 16218 16235 double d = tod(args[0]); 16219 16236 if (d < 0) { 16220 16237 start = (jsoff_t) (d + dlen < 0 ? 0 : d + dlen); 16221 - } else { 16222 - start = (jsoff_t) (d > dlen ? dlen : d); 16223 - } 16238 + } else start = (jsoff_t) (d > dlen ? dlen : d); 16224 16239 } 16225 16240 16226 16241 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 16494 16509 static jsval_t builtin_array_reverse(struct js *js, jsval_t *args, int nargs) { 16495 16510 (void)args; (void)nargs; 16496 16511 jsval_t arr = js->this_val; 16497 - 16512 + 16498 16513 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) 16499 16514 return js_mkerr(js, "reverse called on non-array"); 16500 - 16515 + 16516 + if (is_proxy(js, arr)) { 16517 + jsoff_t len = proxy_aware_length(js, arr); 16518 + if (len <= 1) return arr; 16519 + jsval_t read_from = proxy_read_target(js, arr); 16520 + jsoff_t lower = 0; 16521 + while (lower < len / 2) { 16522 + jsoff_t upper = len - lower - 1; 16523 + char lower_str[16], upper_str[16]; 16524 + size_t lower_len = uint_to_str(lower_str, sizeof(lower_str), (unsigned)lower); 16525 + size_t upper_len = uint_to_str(upper_str, sizeof(upper_str), (unsigned)upper); 16526 + jsoff_t lower_off = lkp(js, read_from, lower_str, lower_len); 16527 + jsoff_t upper_off = lkp(js, read_from, upper_str, upper_len); 16528 + bool lower_exists = lower_off != 0; 16529 + bool upper_exists = upper_off != 0; 16530 + jsval_t lower_val = lower_exists ? resolveprop(js, mkval(T_PROP, lower_off)) : js_mkundef(); 16531 + jsval_t upper_val = upper_exists ? resolveprop(js, mkval(T_PROP, upper_off)) : js_mkundef(); 16532 + if (lower_exists && upper_exists) { 16533 + jsval_t k1 = js_mkstr(js, lower_str, lower_len); 16534 + js_setprop(js, arr, k1, upper_val); 16535 + jsval_t k2 = js_mkstr(js, upper_str, upper_len); 16536 + js_setprop(js, arr, k2, lower_val); 16537 + } else if (upper_exists) { 16538 + jsval_t k1 = js_mkstr(js, lower_str, lower_len); 16539 + js_setprop(js, arr, k1, upper_val); 16540 + } else if (lower_exists) { 16541 + jsval_t k2 = js_mkstr(js, upper_str, upper_len); 16542 + js_setprop(js, arr, k2, lower_val); 16543 + } 16544 + lower++; 16545 + } 16546 + return arr; 16547 + } 16548 + 16501 16549 jsoff_t len_off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16502 16550 jsoff_t len = 0; 16503 16551 if (len_off != 0) { ··· 16505 16553 if (vtype(len_val) == T_NUM) len = (jsoff_t)tod(len_val); 16506 16554 } 16507 16555 if (len <= 1) return arr; 16508 - 16556 + 16509 16557 jsval_t *vals = malloc(len * sizeof(jsval_t)); 16510 16558 jsoff_t *offs = malloc(len * sizeof(jsoff_t)); 16511 16559 if (!vals || !offs) { free(vals); free(offs); return js_mkerr(js, "out of memory"); } 16512 - 16560 + 16513 16561 jsoff_t count = 0; 16514 16562 ant_iter_t iter = js_prop_iter_begin(js, arr); 16515 16563 const char *key; 16516 16564 size_t key_len; 16517 16565 jsval_t val; 16518 - 16566 + 16519 16567 while (js_prop_iter_next(&iter, &key, &key_len, &val)) { 16520 16568 unsigned long parsed_idx; 16521 16569 if (!parse_array_index(key, key_len, len, &parsed_idx) || count >= len) continue; 16522 - 16570 + 16523 16571 vals[count] = val; 16524 16572 offs[count] = iter.off; 16525 16573 count++; 16526 16574 } 16527 16575 js_prop_iter_end(&iter); 16528 - 16576 + 16529 16577 for (jsoff_t i = 0; i < count / 2; i++) { 16530 16578 jsval_t tmp = vals[i]; 16531 16579 vals[i] = vals[count - 1 - i]; 16532 16580 vals[count - 1 - i] = tmp; 16533 16581 } 16534 - 16582 + 16535 16583 for (jsoff_t i = 0; i < count; i++) { 16536 16584 saveval(js, offs[i] + sizeof(jsoff_t) * 2, vals[i]); 16537 16585 } 16538 - 16586 + 16539 16587 free(vals); 16540 16588 free(offs); 16541 16589 return arr; ··· 16850 16898 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 16851 16899 return js_mkerr(js, "fill called on non-array"); 16852 16900 } 16853 - 16901 + 16854 16902 jsval_t value = nargs >= 1 ? args[0] : js_mkundef(); 16855 - 16856 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 16857 - jsoff_t len = 0; 16858 - if (off != 0) { 16859 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 16860 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 16861 - } 16903 + 16904 + jsoff_t len = proxy_aware_length(js, arr); 16862 16905 16863 16906 jsoff_t start = 0, end = len; 16864 16907 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 17235 17278 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 17236 17279 return js_mkerr(js, "shift called on non-array"); 17237 17280 } 17238 - 17239 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17240 - jsoff_t len = 0; 17241 - if (off != 0) { 17242 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17243 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17244 - } 17245 - 17281 + 17282 + jsoff_t len = proxy_aware_length(js, arr); 17246 17283 if (len == 0) return js_mkundef(); 17247 - 17248 - jsoff_t first_off = lkp(js, arr, "0", 1); 17284 + 17285 + jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17286 + jsoff_t first_off = lkp(js, read_from, "0", 1); 17249 17287 jsval_t first = first_off ? resolveprop(js, mkval(T_PROP, first_off)) : js_mkundef(); 17250 - 17288 + 17251 17289 for (jsoff_t i = 1; i < len; i++) { 17252 17290 char src[16], dst[16]; 17253 17291 snprintf(src, sizeof(src), "%u", (unsigned) i); 17254 17292 snprintf(dst, sizeof(dst), "%u", (unsigned)(i - 1)); 17255 - jsoff_t elem_off = lkp(js, arr, src, strlen(src)); 17256 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17257 - jsval_t key = js_mkstr(js, dst, strlen(dst)); 17258 - js_setprop(js, arr, key, elem); 17293 + jsoff_t elem_off = lkp(js, read_from, src, strlen(src)); 17294 + if (elem_off) { 17295 + jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17296 + jsval_t key = js_mkstr(js, dst, strlen(dst)); 17297 + js_setprop(js, arr, key, elem); 17298 + } 17259 17299 } 17260 - 17300 + 17261 17301 jsval_t len_key = js_mkstr(js, "length", 6); 17262 17302 js_setprop(js, arr, len_key, tov((double)(len - 1))); 17263 17303 js->needs_gc = true; ··· 17269 17309 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 17270 17310 return js_mkerr(js, "unshift called on non-array"); 17271 17311 } 17272 - 17273 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17274 - jsoff_t len = 0; 17275 - if (off != 0) { 17276 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17277 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17278 - } 17279 - 17312 + 17313 + jsoff_t len = proxy_aware_length(js, arr); 17314 + jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17315 + 17280 17316 for (int i = (int)len - 1; i >= 0; i--) { 17281 17317 char src[16], dst[16]; 17282 17318 snprintf(src, sizeof(src), "%u", (unsigned) i); 17283 17319 snprintf(dst, sizeof(dst), "%u", (unsigned)(i + nargs)); 17284 - jsoff_t elem_off = lkp(js, arr, src, strlen(src)); 17285 - jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17286 - jsval_t key = js_mkstr(js, dst, strlen(dst)); 17287 - js_setprop(js, arr, key, elem); 17320 + jsoff_t elem_off = lkp(js, read_from, src, strlen(src)); 17321 + if (elem_off) { 17322 + jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17323 + jsval_t key = js_mkstr(js, dst, strlen(dst)); 17324 + js_setprop(js, arr, key, elem); 17325 + } 17288 17326 } 17289 17327 17290 17328 for (int i = 0; i < nargs; i++) { ··· 17478 17516 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 17479 17517 return js_mkerr(js, "splice called on non-array"); 17480 17518 } 17481 - 17482 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17483 - jsoff_t len = 0; 17484 - if (off != 0) { 17485 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17486 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17487 - } 17488 - 17519 + 17520 + jsoff_t len = proxy_aware_length(js, arr); 17521 + jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17522 + 17489 17523 int start = 0; 17490 17524 if (nargs >= 1 && vtype(args[0]) == T_NUM) { 17491 17525 start = (int) tod(args[0]); ··· 17493 17527 if (start < 0) start = 0; 17494 17528 if (start > (int)len) start = (int)len; 17495 17529 } 17496 - 17530 + 17497 17531 int deleteCount = (int)len - start; 17498 17532 if (nargs >= 2 && vtype(args[1]) == T_NUM) { 17499 17533 deleteCount = (int) tod(args[1]); 17500 17534 if (deleteCount < 0) deleteCount = 0; 17501 17535 if (deleteCount > (int)len - start) deleteCount = (int)len - start; 17502 17536 } 17503 - 17537 + 17504 17538 int insertCount = nargs > 2 ? nargs - 2 : 0; 17505 - 17539 + 17506 17540 jsval_t removed = mkarr(js); 17507 17541 if (is_err(removed)) return removed; 17508 - 17542 + 17509 17543 for (int i = 0; i < deleteCount; i++) { 17510 17544 char src[16], dst[16]; 17511 17545 snprintf(src, sizeof(src), "%u", (unsigned)(start + i)); 17512 17546 snprintf(dst, sizeof(dst), "%u", (unsigned) i); 17513 - jsoff_t elem_off = lkp(js, arr, src, strlen(src)); 17547 + jsoff_t elem_off = lkp(js, read_from, src, strlen(src)); 17514 17548 if (elem_off != 0) { 17515 17549 jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 17516 17550 jsval_t key = js_mkstr(js, dst, strlen(dst)); ··· 17519 17553 } 17520 17554 jsval_t rem_len_key = js_mkstr(js, "length", 6); 17521 17555 js_setprop(js, removed, rem_len_key, tov((double) deleteCount)); 17522 - 17556 + 17523 17557 int shift = insertCount - deleteCount; 17524 17558 if (shift > 0) { 17525 17559 for (int i = (int)len - 1; i >= start + deleteCount; i--) { 17526 17560 char src[16], dst[16]; 17527 17561 snprintf(src, sizeof(src), "%u", (unsigned) i); 17528 17562 snprintf(dst, sizeof(dst), "%u", (unsigned)(i + shift)); 17529 - jsoff_t elem_off = lkp(js, arr, src, strlen(src)); 17563 + jsoff_t elem_off = lkp(js, read_from, src, strlen(src)); 17530 17564 jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17531 17565 jsval_t key = js_mkstr(js, dst, strlen(dst)); 17532 17566 js_setprop(js, arr, key, elem); ··· 17536 17570 char src[16], dst[16]; 17537 17571 snprintf(src, sizeof(src), "%u", (unsigned) i); 17538 17572 snprintf(dst, sizeof(dst), "%u", (unsigned)(i + shift)); 17539 - jsoff_t elem_off = lkp(js, arr, src, strlen(src)); 17573 + jsoff_t elem_off = lkp(js, read_from, src, strlen(src)); 17540 17574 jsval_t elem = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17541 17575 jsval_t key = js_mkstr(js, dst, strlen(dst)); 17542 17576 js_setprop(js, arr, key, elem); ··· 17561 17595 if (vtype(arr) != T_ARR && vtype(arr) != T_OBJ) { 17562 17596 return js_mkerr(js, "copyWithin called on non-array"); 17563 17597 } 17564 - 17565 - jsoff_t off = lkp_interned(js, arr, INTERN_LENGTH, 6); 17566 - jsoff_t len = 0; 17567 - if (off != 0) { 17568 - jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 17569 - if (vtype(len_val) == T_NUM) len = (jsoff_t) tod(len_val); 17570 - } 17571 - 17598 + 17599 + jsoff_t len = proxy_aware_length(js, arr); 17600 + jsval_t read_from = is_proxy(js, arr) ? proxy_read_target(js, arr) : arr; 17601 + 17572 17602 int target = 0, start = 0, end = (int)len; 17573 17603 if (nargs >= 1 && vtype(args[0]) == T_NUM) { 17574 17604 target = (int) tod(args[0]); ··· 17585 17615 if (end < 0) end = (int)len + end; 17586 17616 if (end < 0) end = 0; 17587 17617 } 17588 - if (end > (int)len) end = (int)len; 17589 17618 17619 + if (end > (int)len) end = (int)len; 17590 17620 int count = end - start; 17591 17621 if (count > (int)len - target) count = (int)len - target; 17592 - 17622 + 17593 17623 jsval_t *temp = (jsval_t *)malloc(count * sizeof(jsval_t)); 17594 17624 for (int i = 0; i < count; i++) { 17595 17625 char idxstr[16]; 17596 17626 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)(start + i)); 17597 - jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 17627 + jsoff_t elem_off = lkp(js, read_from, idxstr, idxlen); 17598 17628 temp[i] = elem_off ? resolveprop(js, mkval(T_PROP, elem_off)) : js_mkundef(); 17599 17629 } 17600 17630 ··· 17883 17913 17884 17914 static jsval_t builtin_Array_from(struct js *js, jsval_t *args, int nargs) { 17885 17915 if (nargs == 0) return mkarr(js); 17886 - 17916 + 17887 17917 jsval_t src = args[0]; 17888 17918 jsval_t mapFn = (nargs >= 2 && vtype(args[1]) == T_FUNC) ? args[1] : js_mkundef(); 17889 - 17890 - jsval_t result = mkarr(js); 17891 - if (is_err(result)) return result; 17892 - 17919 + 17920 + jsval_t ctor = js->this_val; 17921 + bool use_ctor = (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC); 17922 + jsval_t result; 17923 + 17924 + if (use_ctor) { 17925 + jsval_t ctor_args[1] = { tov(0.0) }; 17926 + result = js_call(js, ctor, ctor_args, 0); 17927 + if (is_err(result)) return result; 17928 + } else { 17929 + result = mkarr(js); 17930 + if (is_err(result)) return result; 17931 + } 17932 + 17933 + bool result_is_proxy = is_proxy(js, result); 17934 + jsval_t write_target = result_is_proxy ? proxy_read_target(js, result) : result; 17935 + 17893 17936 if (vtype(src) == T_STR) { 17894 17937 jsoff_t str_len, str_off = vstr(js, src, &str_len); 17895 17938 const char *str_ptr = (const char *)&js->mem[str_off]; ··· 17903 17946 if (is_err(elem)) return elem; 17904 17947 } 17905 17948 jsval_t key = js_mkstr(js, idxstr, idxlen); 17906 - js_setprop(js, result, key, elem); 17949 + js_setprop(js, write_target, key, elem); 17907 17950 } 17908 17951 jsval_t len_key = js_mkstr(js, "length", 6); 17909 17952 js_setprop(js, result, len_key, tov((double) str_len)); ··· 17925 17968 if (is_err(elem)) return elem; 17926 17969 } 17927 17970 jsval_t key = js_mkstr(js, idxstr, idxlen); 17928 - js_setprop(js, result, key, elem); 17971 + js_setprop(js, write_target, key, elem); 17929 17972 } 17930 17973 jsval_t len_key = js_mkstr(js, "length", 6); 17931 17974 js_setprop(js, result, len_key, tov((double) len)); 17932 17975 } 17933 - 17934 - return mkval(T_ARR, vdata(result)); 17976 + 17977 + if (!use_ctor) return mkval(T_ARR, vdata(result)); 17978 + return result; 17935 17979 } 17936 17980 17937 17981 static jsval_t builtin_Array_of(struct js *js, jsval_t *args, int nargs) { 17938 - jsval_t arr = mkarr(js); 17939 - if (is_err(arr)) return arr; 17940 - 17982 + jsval_t ctor = js->this_val; 17983 + bool use_ctor = (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC); 17984 + jsval_t arr; 17985 + 17986 + if (use_ctor) { 17987 + jsval_t ctor_args[1] = { tov((double)nargs) }; 17988 + arr = js_call(js, ctor, ctor_args, 1); 17989 + if (is_err(arr)) return arr; 17990 + } else { 17991 + arr = mkarr(js); 17992 + if (is_err(arr)) return arr; 17993 + } 17994 + 17995 + bool arr_is_proxy = is_proxy(js, arr); 17996 + jsval_t write_target = arr_is_proxy ? proxy_read_target(js, arr) : arr; 17997 + 17941 17998 for (int i = 0; i < nargs; i++) { 17942 17999 char idxstr[16]; 17943 18000 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 17944 18001 jsval_t key = js_mkstr(js, idxstr, idxlen); 17945 - js_setprop(js, arr, key, args[i]); 18002 + js_setprop(js, write_target, key, args[i]); 17946 18003 } 17947 18004 jsval_t len_key = js_mkstr(js, "length", 6); 17948 18005 js_setprop(js, arr, len_key, tov((double) nargs)); 17949 - return mkval(T_ARR, vdata(arr)); 18006 + 18007 + if (!use_ctor) return mkval(T_ARR, vdata(arr)); 18008 + return arr; 17950 18009 } 17951 18010 17952 18011 static jsval_t builtin_string_indexOf(struct js *js, jsval_t *args, int nargs) { ··· 20648 20707 return result_promise; 20649 20708 } 20650 20709 20710 + static jsval_t handle_proxy_instanceof(struct js *js, jsval_t l, jsval_t r, uint8_t ltype) { 20711 + jsval_t target = proxy_read_target(js, r); 20712 + uint8_t ttype = vtype(target); 20713 + 20714 + if (ttype != T_FUNC && ttype != T_CFUNC) { 20715 + return js_mkerr_typed(js, JS_ERR_TYPE, "Right-hand side of 'instanceof' is not callable"); 20716 + } 20717 + 20718 + const char *hi_key = get_hasInstance_sym_key(); 20719 + if (hi_key && *hi_key) proxy_get(js, r, hi_key, strlen(hi_key)); 20720 + 20721 + jsval_t proto_val = proxy_get(js, r, "prototype", 9); 20722 + uint8_t pt = vtype(proto_val); 20723 + 20724 + if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC) { 20725 + return mkval(T_BOOL, 0); 20726 + } 20727 + 20728 + if (ltype != T_OBJ && ltype != T_ARR && ltype != T_FUNC && ltype != T_PROMISE) { 20729 + return mkval(T_BOOL, 0); 20730 + } 20731 + 20732 + jsval_t current = get_proto(js, l); 20733 + for (int depth = 0; vtype(current) != T_NULL && depth < 32; depth++) { 20734 + if (vdata(current) == vdata(proto_val)) { 20735 + return mkval(T_BOOL, 1); 20736 + } 20737 + current = get_proto(js, current); 20738 + } 20739 + 20740 + return mkval(T_BOOL, 0); 20741 + } 20742 + 20743 + static jsval_t handle_cfunc_instanceof(jsval_t l, jsval_t r, uint8_t ltype) { 20744 + jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(r); 20745 + 20746 + if (fn == builtin_Object) return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 20747 + if (fn == builtin_Function) return mkval(T_BOOL, (ltype == T_FUNC || ltype == T_CFUNC) ? 1 : 0); 20748 + if (fn == builtin_String) return mkval(T_BOOL, ltype == T_STR ? 1 : 0); 20749 + if (fn == builtin_Number) return mkval(T_BOOL, ltype == T_NUM ? 1 : 0); 20750 + if (fn == builtin_Boolean) return mkval(T_BOOL, ltype == T_BOOL ? 1 : 0); 20751 + if (fn == builtin_Array) return mkval(T_BOOL, ltype == T_ARR ? 1 : 0); 20752 + if (fn == builtin_Promise) return mkval(T_BOOL, ltype == T_PROMISE ? 1 : 0); 20753 + 20754 + return mkval(T_BOOL, 0); 20755 + } 20756 + 20757 + static jsval_t walk_prototype_chain(struct js *js, jsval_t l, jsval_t ctor_proto) { 20758 + jsval_t current = get_proto(js, l); 20759 + const int MAX_DEPTH = 32; 20760 + 20761 + for (int depth = 0; vtype(current) != T_NULL && depth < MAX_DEPTH; depth++) { 20762 + if (vdata(current) == vdata(ctor_proto)) return mkval(T_BOOL, 1); 20763 + current = get_proto(js, current); 20764 + } 20765 + 20766 + return mkval(T_BOOL, 0); 20767 + } 20768 + 20651 20769 static jsval_t do_instanceof(struct js *js, jsval_t l, jsval_t r) { 20652 20770 uint8_t ltype = vtype(l); 20653 20771 uint8_t rtype = vtype(r); 20654 20772 20655 20773 if (rtype != T_FUNC && rtype != T_CFUNC) { 20774 + if (is_proxy(js, r)) return handle_proxy_instanceof(js, l, r, ltype); 20656 20775 return js_mkerr_typed(js, JS_ERR_TYPE, "Right-hand side of 'instanceof' is not callable"); 20657 20776 } 20658 20777 20659 20778 if (rtype == T_CFUNC) { 20660 - // handle legacy T_CFUNC 20661 - jsval_t (*fn)(struct js *, jsval_t *, int) = (jsval_t(*)(struct js *, jsval_t *, int)) vdata(r); 20662 - if (fn == builtin_Object) { 20663 - return mkval(T_BOOL, ltype == T_OBJ ? 1 : 0); 20664 - } else if (fn == builtin_Function) { 20665 - return mkval(T_BOOL, (ltype == T_FUNC || ltype == T_CFUNC) ? 1 : 0); 20666 - } else if (fn == builtin_String) { 20667 - return mkval(T_BOOL, ltype == T_STR ? 1 : 0); 20668 - } else if (fn == builtin_Number) { 20669 - return mkval(T_BOOL, ltype == T_NUM ? 1 : 0); 20670 - } else if (fn == builtin_Boolean) { 20671 - return mkval(T_BOOL, ltype == T_BOOL ? 1 : 0); 20672 - } else if (fn == builtin_Array) { 20673 - return mkval(T_BOOL, ltype == T_ARR ? 1 : 0); 20674 - } else if (fn == builtin_Promise) { 20675 - return mkval(T_BOOL, ltype == T_PROMISE ? 1 : 0); 20676 - } 20677 - return mkval(T_BOOL, 0); 20779 + return handle_cfunc_instanceof(l, r, ltype); 20678 20780 } 20679 20781 20680 20782 jsval_t func_obj = mkval(T_OBJ, vdata(r)); 20681 20783 jsoff_t proto_off = lkp_interned(js, func_obj, INTERN_PROTOTYPE, 9); 20682 20784 if (proto_off == 0) return mkval(T_BOOL, 0); 20683 - jsval_t ctor_proto = resolveprop(js, mkval(T_PROP, proto_off)); 20684 20785 20786 + jsval_t ctor_proto = resolveprop(js, mkval(T_PROP, proto_off)); 20685 20787 uint8_t pt = vtype(ctor_proto); 20686 20788 if (pt != T_OBJ && pt != T_ARR && pt != T_FUNC) return mkval(T_BOOL, 0); 20687 20789 ··· 20694 20796 return mkval(T_BOOL, 0); 20695 20797 } 20696 20798 20697 - jsval_t current = get_proto(js, l); 20698 - int depth = 0; 20699 - const int MAX_DEPTH = 32; 20700 - 20701 - while (vtype(current) != T_NULL && depth < MAX_DEPTH) { 20702 - if (vdata(current) == vdata(ctor_proto)) return mkval(T_BOOL, 1); 20703 - current = get_proto(js, current); 20704 - depth++; 20705 - } 20706 - 20707 - return mkval(T_BOOL, 0); 20799 + return walk_prototype_chain(js, l, ctor_proto); 20708 20800 } 20709 20801 20710 20802 static jsval_t do_in(struct js *js, jsval_t l, jsval_t r) { ··· 21720 21812 return get_proxy_data(obj) != NULL; 21721 21813 } 21722 21814 21815 + static jsval_t proxy_read_target(struct js *js, jsval_t obj) { 21816 + proxy_data_t *data = get_proxy_data(obj); 21817 + return data ? data->target : obj; 21818 + } 21819 + 21820 + static jsoff_t proxy_aware_length(struct js *js, jsval_t obj) { 21821 + jsval_t src = is_proxy(js, obj) ? proxy_read_target(js, obj) : obj; 21822 + jsoff_t off = lkp_interned(js, src, INTERN_LENGTH, 6); 21823 + if (off == 0) return 0; 21824 + jsval_t len_val = resolveprop(js, mkval(T_PROP, off)); 21825 + return vtype(len_val) == T_NUM ? (jsoff_t)tod(len_val) : 0; 21826 + } 21827 + 21828 + static jsval_t proxy_aware_get_elem(struct js *js, jsval_t obj, const char *key, size_t key_len) { 21829 + jsval_t src = is_proxy(js, obj) ? proxy_read_target(js, obj) : obj; 21830 + jsoff_t off = lkp(js, src, key, key_len); 21831 + return off ? resolveprop(js, mkval(T_PROP, off)) : js_mkundef(); 21832 + } 21833 + 21723 21834 static jsval_t throw_proxy_error(struct js *js, const char *message) { 21724 21835 jsval_t err_obj = mkobj(js, 0); 21725 21836 js_setprop(js, err_obj, js_mkstr(js, "message", 7), js_mkstr(js, message, strlen(message))); ··· 21735 21846 jsval_t target = data->target; 21736 21847 jsval_t handler = data->handler; 21737 21848 21738 - jsoff_t get_trap_off = vtype(handler) == T_OBJ ? lkp_interned(js, handler, INTERN_GET, 3) : 0; 21849 + jsoff_t get_trap_off = vtype(handler) == T_OBJ 21850 + ? lkp_interned(js, handler, INTERN_GET, 3) 21851 + : 0; 21852 + 21739 21853 if (get_trap_off != 0) { 21740 21854 jsval_t get_trap = resolveprop(js, mkval(T_PROP, get_trap_off)); 21741 21855 if (vtype(get_trap) == T_FUNC || vtype(get_trap) == T_CFUNC) { 21742 - jsval_t key_val = js_mkstr(js, key, key_len); 21856 + jsval_t key_val; 21857 + if (is_symbol_key(key, key_len)) { 21858 + key_val = get_wellknown_sym_by_key(key, key_len); 21859 + if (key_val == 0) key_val = js_mkstr(js, key, key_len); 21860 + } else key_val = js_mkstr(js, key, key_len); 21861 + 21743 21862 jsval_t args[3] = { target, key_val, proxy }; 21744 21863 return js_call(js, get_trap, args, 3); 21745 21864 }
+22 -1
src/modules/symbol.c
··· 38 38 { &g_species.sym, "Symbol.species" }, 39 39 }; 40 40 41 + bool is_symbol_key(const char *key, size_t key_len) { 42 + return 43 + key_len > 7 44 + && memcmp(key, "__sym_", 6) == 0 45 + && key[key_len - 1] == '_' 46 + && key[key_len - 2] == '_'; 47 + } 48 + 49 + jsval_t get_wellknown_sym_by_key(const char *key, size_t key_len) { 50 + static const struct { wellknown_sym_t *sym; } table[] = { 51 + { &g_iterator }, { &g_asyncIterator }, { &g_toStringTag }, 52 + { &g_hasInstance }, { &g_observable }, { &g_toPrimitive }, { &g_species } 53 + }; 54 + for (size_t i = 0; i < sizeof(table)/sizeof(table[0]); i++) { 55 + if (table[i].sym->key[0] && strlen(table[i].sym->key) == key_len && 56 + memcmp(table[i].sym->key, key, key_len) == 0) 57 + return table[i].sym->sym; 58 + } 59 + return (jsval_t)0; 60 + } 61 + 41 62 const char *get_symbol_description_from_key(const char *sym_key, size_t key_len) { 42 - if (key_len < 9 || memcmp(sym_key, "__sym_", 6) != 0) return NULL; 63 + if (!is_symbol_key(sym_key, key_len)) return NULL; 43 64 44 65 uint64_t id = 0; 45 66 for (const char *p = sym_key + 6; *p >= '0' && *p <= '9'; p++) id = id * 10 + (*p - '0');