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.

shrink frame from 4kb to 3kb per loop

+342 -318
+340 -311
src/ant.c
··· 8172 8172 return res; 8173 8173 } 8174 8174 8175 + __attribute__((noinline)) 8176 + static jsval_t do_call_bound_cfunc(struct js *js, jsval_t func, jsval_t func_obj, jsval_t cfunc_slot, jsval_t target_this) { 8177 + jsval_t bound_this_slot = get_slot(js, func_obj, SLOT_BOUND_THIS); 8178 + bool has_bound_this = vtype(bound_this_slot) != T_UNDEF; 8179 + 8180 + if (has_bound_this) { 8181 + pop_this(); 8182 + push_this(bound_this_slot); 8183 + } 8184 + 8185 + jsval_t saved_func = js->current_func; 8186 + js->current_func = func; 8187 + 8188 + int bound_argc; 8189 + jsval_t *bound_args = resolve_bound_args(js, func_obj, NULL, 0, &bound_argc); 8190 + 8191 + jsval_t res; 8192 + if (!bound_args) { 8193 + res = call_c(js, (jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot)); 8194 + } else { 8195 + UT_array *args_arr; 8196 + utarray_new(args_arr, &jsval_icd); 8197 + for (int i = 0; i < bound_argc; i++) utarray_push_back(args_arr, &bound_args[i]); 8198 + free(bound_args); 8199 + 8200 + jsval_t err; 8201 + int call_argc = parse_call_args(js, args_arr, &err); 8202 + if (call_argc < 0) { 8203 + utarray_free(args_arr); 8204 + js->current_func = saved_func; 8205 + if (has_bound_this) pop_this(); 8206 + return err; 8207 + } 8208 + 8209 + jsval_t *argv = (jsval_t *)utarray_front(args_arr); 8210 + int total_argc = (int)utarray_len(args_arr); 8211 + jsval_t saved_this = js->this_val; 8212 + js->this_val = peek_this(); 8213 + res = ((jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot))(js, argv, total_argc); 8214 + js->this_val = saved_this; 8215 + utarray_free(args_arr); 8216 + } 8217 + 8218 + js->current_func = saved_func; 8219 + 8220 + if (has_bound_this) { 8221 + pop_this(); 8222 + push_this(target_this); 8223 + } 8224 + 8225 + return res; 8226 + } 8227 + 8228 + __attribute__((noinline)) 8229 + static jsval_t do_call_init_fields(struct js *js, jsval_t func_obj, jsval_t target_this) { 8230 + jsval_t count_val = get_slot(js, func_obj, SLOT_FIELD_COUNT); 8231 + if (vtype(count_val) != T_NUM || vtype(target_this) != T_OBJ) return js_mkundef(); 8232 + 8233 + int field_count = (int)tod(count_val); 8234 + jsval_t src_val = get_slot(js, func_obj, SLOT_SOURCE); 8235 + jsval_t fields_meta = get_slot(js, func_obj, SLOT_FIELDS); 8236 + if (vtype(src_val) == T_UNDEF || vtype(fields_meta) == T_UNDEF) return js_mkundef(); 8237 + 8238 + if (vtype(src_val) != T_CFUNC) return js_mkundef(); 8239 + const char *source = (const char *)vdata(src_val); 8240 + 8241 + jsoff_t meta_len, meta_ptr_off = vstr(js, fields_meta, &meta_len); 8242 + const jsoff_t *metadata = (const jsoff_t *)(&js->mem[meta_ptr_off]); 8243 + 8244 + for (int i = 0; i < field_count; i++) { 8245 + jsoff_t name_off = metadata[i * 5 + 0]; 8246 + jsoff_t name_len = metadata[i * 5 + 1]; 8247 + jsoff_t init_start = metadata[i * 5 + 2]; 8248 + jsoff_t init_end = metadata[i * 5 + 3]; 8249 + bool computed = metadata[i * 5 + 4] != 0; 8250 + 8251 + jsval_t fname; 8252 + if (computed) fname = (jsval_t) name_off; 8253 + else fname = js_mkstr(js, &source[name_off], name_len); 8254 + 8255 + if (is_err(fname)) return fname; 8256 + 8257 + jsval_t field_val = js_mkundef(); 8258 + if (init_start > 0 && init_end > init_start) { 8259 + field_val = js_eval_str(js, &source[init_start], init_end - init_start); 8260 + field_val = resolveprop(js, field_val); 8261 + } 8262 + 8263 + jsval_t set_res = js_setprop(js, target_this, fname, field_val); 8264 + if (is_err(set_res)) return set_res; 8265 + } 8266 + 8267 + return js_mkundef(); 8268 + } 8269 + 8270 + __attribute__((noinline)) 8271 + static jsval_t do_call_async(struct js *js, const char *code_str, jsoff_t fnlen, jsval_t closure_scope, jsval_t *bound_args, int bound_argc) { 8272 + UT_array *call_args; 8273 + utarray_new(call_args, &jsval_icd); 8274 + for (int i = 0; i < bound_argc; i++) utarray_push_back(call_args, &bound_args[i]); 8275 + jsval_t err; 8276 + int call_argc = parse_call_args(js, call_args, &err); 8277 + if (call_argc < 0) { 8278 + utarray_free(call_args); 8279 + return err; 8280 + } 8281 + jsval_t *argv = (jsval_t *)utarray_front(call_args); 8282 + int argc = (int)utarray_len(call_args); 8283 + jsval_t res = start_async_in_coroutine(js, code_str, fnlen, closure_scope, argv, argc); 8284 + utarray_free(call_args); 8285 + return res; 8286 + } 8287 + 8175 8288 static jsval_t do_call_op(struct js *js, jsval_t func, jsval_t args) { 8176 8289 if (js_stack_overflow(js)) { 8177 8290 return js_mkerr_typed(js, JS_ERR_RANGE | JS_ERR_NO_STACK, "Maximum call stack size exceeded"); ··· 8240 8353 jsval_t func_obj = mkval(T_OBJ, vdata(func)); 8241 8354 jsval_t cfunc_slot = get_slot(js, func_obj, SLOT_CFUNC); 8242 8355 if (vtype(cfunc_slot) == T_CFUNC) { 8243 - jsval_t bound_this_slot = get_slot(js, func_obj, SLOT_BOUND_THIS); 8244 - bool has_bound_this = vtype(bound_this_slot) != T_UNDEF; 8245 - 8246 - if (has_bound_this) { 8247 - pop_this(); 8248 - push_this(bound_this_slot); 8249 - } 8250 - 8251 - jsval_t saved_func = js->current_func; 8252 - js->current_func = func; 8253 - 8254 - int bound_argc; 8255 - jsval_t *bound_args = resolve_bound_args(js, func_obj, NULL, 0, &bound_argc); 8256 - 8257 - if (!bound_args) { 8258 - res = call_c(js, (jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot)); 8259 - } else { 8260 - UT_array *args_arr; 8261 - utarray_new(args_arr, &jsval_icd); 8262 - for (int i = 0; i < bound_argc; i++) utarray_push_back(args_arr, &bound_args[i]); 8263 - free(bound_args); 8264 - 8265 - jsval_t err; 8266 - int call_argc = parse_call_args(js, args_arr, &err); 8267 - if (call_argc < 0) { 8268 - utarray_free(args_arr); 8269 - js->current_func = saved_func; 8270 - if (has_bound_this) pop_this(); 8271 - return err; 8272 - } 8273 - 8274 - jsval_t *argv = (jsval_t *)utarray_front(args_arr); 8275 - int total_argc = (int)utarray_len(args_arr); 8276 - jsval_t saved_this = js->this_val; 8277 - js->this_val = peek_this(); 8278 - res = ((jsval_t(*)(struct js *, jsval_t *, int)) vdata(cfunc_slot))(js, argv, total_argc); 8279 - js->this_val = saved_this; 8280 - utarray_free(args_arr); 8281 - } 8282 - 8283 - js->current_func = saved_func; 8284 - 8285 - if (has_bound_this) { 8286 - pop_this(); 8287 - push_this(target_this); 8288 - } 8356 + res = do_call_bound_cfunc(js, func, func_obj, cfunc_slot, target_this); 8289 8357 } else { 8290 8358 jsval_t builtin_slot = get_slot(js, func_obj, SLOT_BUILTIN); 8291 8359 if (vtype(builtin_slot) == T_NUM && (int)tod(builtin_slot) == BUILTIN_OBJECT) res = call_c(js, builtin_Object); else { ··· 8357 8425 pop_call_frame(); goto restore_state; 8358 8426 } 8359 8427 } 8360 - 8361 - jsval_t count_val = get_slot(js, func_obj, SLOT_FIELD_COUNT); 8362 - if (vtype(count_val) != T_NUM || vtype(target_this) != T_OBJ) goto skip_fields; 8363 - 8364 - int field_count = (int)tod(count_val); 8365 - jsval_t src_val = get_slot(js, func_obj, SLOT_SOURCE); 8366 - jsval_t fields_meta = get_slot(js, func_obj, SLOT_FIELDS); 8367 - if (vtype(src_val) == T_UNDEF || vtype(fields_meta) == T_UNDEF) goto skip_fields; 8368 - 8369 - if (vtype(src_val) != T_CFUNC) goto skip_fields; 8370 - const char *source = (const char *)vdata(src_val); 8371 - 8372 - jsoff_t meta_len, meta_ptr_off = vstr(js, fields_meta, &meta_len); 8373 - const jsoff_t *metadata = (const jsoff_t *)(&js->mem[meta_ptr_off]); 8374 - 8375 - for (int i = 0; i < field_count; i++) { 8376 - jsoff_t name_off = metadata[i * 5 + 0]; 8377 - jsoff_t name_len = metadata[i * 5 + 1]; 8378 - jsoff_t init_start = metadata[i * 5 + 2]; 8379 - jsoff_t init_end = metadata[i * 5 + 3]; 8380 - bool computed = metadata[i * 5 + 4] != 0; 8381 - 8382 - jsval_t fname; 8383 - if (computed) fname = (jsval_t) name_off; 8384 - else fname = js_mkstr(js, &source[name_off], name_len); 8385 - 8386 - if (is_err(fname)) { 8428 + { 8429 + jsval_t field_err = do_call_init_fields(js, func_obj, target_this); 8430 + if (is_err(field_err)) { 8387 8431 js->current_func = saved_func; 8388 8432 pop_call_frame(); 8389 - return fname; 8390 - } 8391 - 8392 - jsval_t field_val = js_mkundef(); 8393 - if (init_start > 0 && init_end > init_start) { 8394 - field_val = js_eval_str(js, &source[init_start], init_end - init_start); 8395 - field_val = resolveprop(js, field_val); 8396 - } 8397 - 8398 - jsval_t set_res = js_setprop(js, target_this, fname, field_val); 8399 - if (is_err(set_res)) { 8400 - js->current_func = saved_func; 8401 - pop_call_frame(); 8402 - return set_res; 8433 + return field_err; 8403 8434 } 8404 8435 } 8405 - skip_fields: 8406 8436 if (is_async) { 8407 - UT_array *call_args; 8408 - utarray_new(call_args, &jsval_icd); 8409 - for (int i = 0; i < bound_argc; i++) utarray_push_back(call_args, &bound_args[i]); 8410 - jsval_t err; 8411 - int call_argc = parse_call_args(js, call_args, &err); 8412 - if (call_argc < 0) { 8413 - utarray_free(call_args); 8437 + res = do_call_async(js, code_str, fnlen, closure_scope, bound_args, bound_argc); 8438 + if (is_err(res)) { 8414 8439 pop_call_frame(); 8415 8440 if (bound_args) free(bound_args); 8416 8441 js->super_val = saved_super; 8417 8442 js->current_func = saved_func; 8418 - return err; 8443 + return res; 8419 8444 } 8420 - jsval_t *argv = (jsval_t *)utarray_front(call_args); 8421 - int argc = (int)utarray_len(call_args); 8422 - res = start_async_in_coroutine(js, code_str, fnlen, closure_scope, argv, argc); 8423 - utarray_free(call_args); 8424 8445 } else if (is_tail && vtype(js->new_target) == T_UNDEF) { 8425 8446 UT_array *tc_args_arr; 8426 8447 utarray_new(tc_args_arr, &jsval_icd); ··· 10478 10499 return js_mkundef(); 10479 10500 } 10480 10501 10481 - static jsval_t js_unary(struct js *js) { 10482 - uint8_t tok = next(js); 10502 + __attribute__((noinline)) 10503 + static jsval_t js_unary_new(struct js *js) { 10504 + js->consumed = 1; 10505 + if (next(js) == TOK_DOT) { 10506 + js->consumed = 1; 10507 + if (next(js) != TOK_IDENTIFIER || !streq(&js->code[js->toff], js->tlen, "target", 6)) { 10508 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 10509 + } 10510 + js->consumed = 1; 10511 + return mkntarg(NTARG_NEW_TARGET); 10512 + } 10483 10513 10484 - static const void *dispatch[] = { 10485 - [TOK_NEW] = &&do_new, 10486 - [TOK_DELETE] = &&do_delete, 10487 - [TOK_AWAIT] = &&do_await, 10488 - [TOK_POSTINC] = &&do_prefix_inc, 10489 - [TOK_POSTDEC] = &&do_prefix_inc, 10490 - [TOK_NOT] = &&do_unary_op, 10491 - [TOK_TILDA] = &&do_unary_op, 10492 - [TOK_TYPEOF] = &&do_typeof, 10493 - [TOK_VOID] = &&do_unary_op, 10494 - [TOK_MINUS] = &&do_unary_op, 10495 - [TOK_PLUS] = &&do_unary_op, 10496 - }; 10514 + jsval_t obj = mkobj(js, 0); 10515 + jsval_t saved_this = js->this_val; 10516 + jsval_t saved_new_target = js->new_target; 10497 10517 10498 - if (tok < sizeof(dispatch)/sizeof(dispatch[0]) && dispatch[tok]) { 10499 - goto *dispatch[tok]; 10500 - } 10501 - return js_postfix(js); 10518 + jsval_t ctor = js_group(js); 10519 + if (is_err(ctor)) { return ctor; } 10502 10520 10503 - do_new: { 10504 - js->consumed = 1; 10505 - if (next(js) == TOK_DOT) { 10521 + while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET) { 10522 + ctor = resolve_coderef(js, ctor); 10523 + if (is_err(ctor)) { return ctor; } 10524 + 10525 + if (js->tok == TOK_DOT) { 10506 10526 js->consumed = 1; 10507 - if (next(js) != TOK_IDENTIFIER || !streq(&js->code[js->toff], js->tlen, "target", 6)) { 10527 + if (next(js) != TOK_IDENTIFIER && !is_keyword_propname(js->tok)) { 10508 10528 return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 10509 10529 } 10510 10530 js->consumed = 1; 10511 - return mkntarg(NTARG_NEW_TARGET); 10531 + ctor = do_op(js, TOK_DOT, ctor, mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen)); 10532 + } else { 10533 + js->consumed = 1; 10534 + jsval_t idx = js_expr(js); 10535 + if (is_err(idx)) { return idx; } 10536 + if (next(js) != TOK_RBRACKET) { return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); } 10537 + js->consumed = 1; 10538 + ctor = do_op(js, TOK_BRACKET, ctor, idx); 10512 10539 } 10540 + } 10513 10541 10514 - jsval_t obj = mkobj(js, 0); 10515 - jsval_t saved_this = js->this_val; 10516 - jsval_t saved_new_target = js->new_target; 10542 + ctor = resolve_coderef(js, ctor); 10543 + if (is_err(ctor)) { return ctor; } 10544 + if (vtype(ctor) == T_PROP || vtype(ctor) == T_PROPREF) ctor = resolveprop(js, ctor); 10545 + if (vtype(obj) == T_OBJ && (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC)) set_slot(js, obj, SLOT_CTOR, ctor); 10546 + js->pending_ntg = ctor; 10517 10547 10518 - jsval_t ctor = js_group(js); 10519 - if (is_err(ctor)) { return ctor; } 10548 + jsval_t result; 10549 + push_this(obj); 10550 + if (next(js) == TOK_LPAREN) { 10551 + jsval_t params = js_call_params(js); 10552 + if (is_err(params)) { 10553 + pop_this(); 10554 + js->pending_ntg = js_mkundef(); 10555 + js->new_target = saved_new_target; return params; 10556 + } 10557 + result = do_op(js, TOK_CALL, ctor, params); 10558 + } else { 10559 + result = do_op(js, TOK_CALL, ctor, mkcoderef(0, 0)); 10560 + js->consumed = 0; 10561 + } 10562 + 10563 + jsval_t constructed_obj = peek_this(); 10564 + pop_this(); 10565 + 10566 + js->this_val = saved_this; 10567 + js->new_target = saved_new_target; 10568 + 10569 + if (is_err(result)) return result; 10570 + 10571 + uint8_t rtype = vtype(result); 10572 + jsval_t new_result = ( 10573 + rtype == T_OBJ || rtype == T_ARR || 10574 + rtype == T_PROMISE || rtype == T_FUNC 10575 + ) ? result : constructed_obj; 10576 + 10577 + if (vtype(new_result) == T_OBJ && (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC)) { 10578 + set_slot(js, new_result, SLOT_CTOR, ctor); 10579 + } 10520 10580 10521 - while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET) { 10522 - ctor = resolve_coderef(js, ctor); 10523 - if (is_err(ctor)) { return ctor; } 10524 - 10525 - if (js->tok == TOK_DOT) { 10526 - js->consumed = 1; 10581 + jsval_t call_obj = js_mkundef(); 10582 + while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET || next(js) == TOK_OPTIONAL_CHAIN || next(js) == TOK_LPAREN) { 10583 + uint8_t op = js->tok; 10584 + if (op == TOK_DOT || op == TOK_OPTIONAL_CHAIN) { 10585 + js->consumed = 1; 10586 + call_obj = new_result; 10587 + if (op == TOK_OPTIONAL_CHAIN && (vtype(call_obj) == T_NULL || vtype(call_obj) == T_UNDEF)) { 10588 + new_result = call_obj = js_mkundef(); 10589 + } else { 10527 10590 if (next(js) != TOK_IDENTIFIER && !is_keyword_propname(js->tok)) { 10528 10591 return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 10529 10592 } 10530 10593 js->consumed = 1; 10531 - ctor = do_op(js, TOK_DOT, ctor, mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen)); 10532 - } else { 10533 - js->consumed = 1; 10534 - jsval_t idx = js_expr(js); 10535 - if (is_err(idx)) { return idx; } 10536 - if (next(js) != TOK_RBRACKET) { return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); } 10537 - js->consumed = 1; 10538 - ctor = do_op(js, TOK_BRACKET, ctor, idx); 10594 + new_result = do_op(js, op, new_result, mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen)); 10539 10595 } 10596 + } else if (op == TOK_LBRACKET) { 10597 + js->consumed = 1; 10598 + call_obj = new_result; 10599 + jsval_t idx = js_expr(js); 10600 + if (is_err(idx)) return idx; 10601 + if (next(js) != TOK_RBRACKET) return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); 10602 + js->consumed = 1; 10603 + new_result = do_op(js, TOK_BRACKET, new_result, idx); 10604 + } else { 10605 + jsval_t func_this = vtype(call_obj) == T_UNDEF ? js->this_val : call_obj; 10606 + push_this(func_this); 10607 + jsval_t params = js_call_params(js); 10608 + if (is_err(params)) { pop_this(); return params; } 10609 + new_result = do_op(js, TOK_CALL, new_result, params); 10610 + pop_this(); 10611 + call_obj = js_mkundef(); 10540 10612 } 10613 + } 10614 + return new_result; 10615 + } 10541 10616 10542 - ctor = resolve_coderef(js, ctor); 10543 - if (is_err(ctor)) { return ctor; } 10544 - if (vtype(ctor) == T_PROP || vtype(ctor) == T_PROPREF) ctor = resolveprop(js, ctor); 10545 - if (vtype(obj) == T_OBJ && (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC)) set_slot(js, obj, SLOT_CTOR, ctor); 10546 - js->pending_ntg = ctor; 10617 + __attribute__((noinline)) 10618 + static jsval_t js_unary_delete(struct js *js) { 10619 + js->consumed = 1; 10547 10620 10548 - jsval_t result; 10549 - push_this(obj); 10550 - if (next(js) == TOK_LPAREN) { 10551 - jsval_t params = js_call_params(js); 10552 - if (is_err(params)) { 10553 - pop_this(); 10554 - js->pending_ntg = js_mkundef(); 10555 - js->new_target = saved_new_target; return params; 10556 - } 10557 - result = do_op(js, TOK_CALL, ctor, params); 10558 - } else { 10559 - result = do_op(js, TOK_CALL, ctor, mkcoderef(0, 0)); 10560 - js->consumed = 0; 10561 - } 10562 - 10563 - jsval_t constructed_obj = peek_this(); 10564 - pop_this(); 10565 - 10566 - js->this_val = saved_this; 10567 - js->new_target = saved_new_target; 10568 - 10569 - if (is_err(result)) return result; 10570 - 10571 - uint8_t rtype = vtype(result); 10572 - jsval_t new_result = ( 10573 - rtype == T_OBJ || rtype == T_ARR || 10574 - rtype == T_PROMISE || rtype == T_FUNC 10575 - ) ? result : constructed_obj; 10576 - 10577 - if (vtype(new_result) == T_OBJ && (vtype(ctor) == T_FUNC || vtype(ctor) == T_CFUNC)) { 10578 - set_slot(js, new_result, SLOT_CTOR, ctor); 10579 - } 10580 - 10581 - jsval_t call_obj = js_mkundef(); 10582 - while (next(js) == TOK_DOT || next(js) == TOK_LBRACKET || next(js) == TOK_OPTIONAL_CHAIN || next(js) == TOK_LPAREN) { 10583 - uint8_t op = js->tok; 10584 - if (op == TOK_DOT || op == TOK_OPTIONAL_CHAIN) { 10585 - js->consumed = 1; 10586 - call_obj = new_result; 10587 - if (op == TOK_OPTIONAL_CHAIN && (vtype(call_obj) == T_NULL || vtype(call_obj) == T_UNDEF)) { 10588 - new_result = call_obj = js_mkundef(); 10589 - } else { 10590 - if (next(js) != TOK_IDENTIFIER && !is_keyword_propname(js->tok)) { 10591 - return js_mkerr_typed(js, JS_ERR_SYNTAX, "identifier expected"); 10592 - } 10593 - js->consumed = 1; 10594 - new_result = do_op(js, op, new_result, mkcoderef((jsoff_t)js->toff, (jsoff_t)js->tlen)); 10595 - } 10596 - } else if (op == TOK_LBRACKET) { 10597 - js->consumed = 1; 10598 - call_obj = new_result; 10599 - jsval_t idx = js_expr(js); 10600 - if (is_err(idx)) return idx; 10601 - if (next(js) != TOK_RBRACKET) return js_mkerr_typed(js, JS_ERR_SYNTAX, "] expected"); 10602 - js->consumed = 1; 10603 - new_result = do_op(js, TOK_BRACKET, new_result, idx); 10604 - } else { 10605 - jsval_t func_this = vtype(call_obj) == T_UNDEF ? js->this_val : call_obj; 10606 - push_this(func_this); 10607 - jsval_t params = js_call_params(js); 10608 - if (is_err(params)) { pop_this(); return params; } 10609 - new_result = do_op(js, TOK_CALL, new_result, params); 10610 - pop_this(); 10611 - call_obj = js_mkundef(); 10612 - } 10621 + if ((js->flags & F_STRICT) && next(js) == TOK_IDENTIFIER) { 10622 + jsoff_t id_pos = js->pos; 10623 + uint8_t id_tok = js->tok; 10624 + jsoff_t id_toff = js->toff, id_tlen = js->tlen; 10625 + int id_stream_pos = js->token_stream_pos; 10626 + js->consumed = 1; 10627 + uint8_t after = next(js); 10628 + if (after != TOK_DOT && after != TOK_LBRACKET && after != TOK_OPTIONAL_CHAIN) { 10629 + return js_mkerr_typed(js, JS_ERR_SYNTAX, "cannot delete unqualified identifier in strict mode"); 10613 10630 } 10614 - return new_result; 10631 + js->pos = id_pos; js->tok = id_tok; js->toff = id_toff; js->tlen = id_tlen; js->consumed = 0; 10632 + js->token_stream_pos = id_stream_pos; 10615 10633 } 10616 10634 10617 - do_delete: { 10618 - js->consumed = 1; 10635 + js_parse_state_t saved_state; 10636 + JS_SAVE_STATE(js, saved_state); 10637 + uint8_t saved_flags = js->flags; 10638 + jsval_t operand = js_postfix(js); 10619 10639 10620 - if ((js->flags & F_STRICT) && next(js) == TOK_IDENTIFIER) { 10621 - jsoff_t id_pos = js->pos; 10622 - uint8_t id_tok = js->tok; 10623 - jsoff_t id_toff = js->toff, id_tlen = js->tlen; 10624 - int id_stream_pos = js->token_stream_pos; 10625 - js->consumed = 1; 10626 - uint8_t after = next(js); 10627 - if (after != TOK_DOT && after != TOK_LBRACKET && after != TOK_OPTIONAL_CHAIN) { 10628 - return js_mkerr_typed(js, JS_ERR_SYNTAX, "cannot delete unqualified identifier in strict mode"); 10629 - } 10630 - js->pos = id_pos; js->tok = id_tok; js->toff = id_toff; js->tlen = id_tlen; js->consumed = 0; 10631 - js->token_stream_pos = id_stream_pos; 10632 - } 10640 + if (is_err(operand)) { 10641 + JS_RESTORE_STATE(js, saved_state); 10642 + js->flags = (saved_flags & ~F_THROW) | F_NOEXEC; 10643 + js_postfix(js); 10644 + js->flags = saved_flags; 10645 + return js_true; 10646 + } 10647 + if (js->flags & F_NOEXEC) return js_true; 10633 10648 10634 - js_parse_state_t saved_state; 10635 - JS_SAVE_STATE(js, saved_state); 10636 - uint8_t saved_flags = js->flags; 10637 - jsval_t operand = js_postfix(js); 10649 + if (vtype(operand) == T_PROPREF) { 10650 + jsoff_t obj_off = propref_obj(operand); 10651 + jsoff_t key_off = propref_key(operand); 10652 + jsval_t obj = mkval(T_OBJ, obj_off); 10653 + jsval_t key = mkval(T_STR, key_off); 10654 + jsoff_t len; 10655 + const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 10638 10656 10639 - if (is_err(operand)) { 10640 - JS_RESTORE_STATE(js, saved_state); 10641 - js->flags = (saved_flags & ~F_THROW) | F_NOEXEC; 10642 - js_postfix(js); 10643 - js->flags = saved_flags; 10644 - return js_true; 10657 + if (is_proxy(js, obj)) { 10658 + jsval_t result = proxy_delete(js, obj, key_str, len); 10659 + return is_err(result) ? result : js_bool(js_truthy(js, result)); 10645 10660 } 10646 - if (js->flags & F_NOEXEC) return js_true; 10647 10661 10648 - if (vtype(operand) == T_PROPREF) { 10649 - jsoff_t obj_off = propref_obj(operand); 10650 - jsoff_t key_off = propref_key(operand); 10651 - jsval_t obj = mkval(T_OBJ, obj_off); 10652 - jsval_t key = mkval(T_STR, key_off); 10653 - jsoff_t len; 10654 - const char *key_str = (const char *)&js->mem[vstr(js, key, &len)]; 10662 + jsval_t err = check_frozen_sealed(js, obj, "delete"); 10663 + if (vtype(err) != T_UNDEF) return err; 10655 10664 10656 - if (is_proxy(js, obj)) { 10657 - jsval_t result = proxy_delete(js, obj, key_str, len); 10658 - return is_err(result) ? result : js_bool(js_truthy(js, result)); 10665 + if (is_arr_off(js, obj_off)) { 10666 + jsoff_t doff = get_dense_buf_off(js, obj_off); 10667 + unsigned long del_idx; 10668 + if (doff && parse_array_index(key_str, len, dense_length(js, doff), &del_idx)) { 10669 + arr_del(js, mkval(T_ARR, (uint64_t)obj_off), (jsoff_t)del_idx); 10670 + return js_true; 10659 10671 } 10672 + } 10660 10673 10661 - jsval_t err = check_frozen_sealed(js, obj, "delete"); 10662 - if (vtype(err) != T_UNDEF) return err; 10674 + jsoff_t prop_off = lkp(js, obj, key_str, len); 10675 + if (prop_off == 0) { 10676 + try_dynamic_deleter(js, obj, key_str, len); 10677 + return js_true; 10678 + } 10663 10679 10664 - if (is_arr_off(js, obj_off)) { 10665 - jsoff_t doff = get_dense_buf_off(js, obj_off); 10666 - unsigned long del_idx; 10667 - if (doff && parse_array_index(key_str, len, dense_length(js, doff), &del_idx)) { 10668 - arr_del(js, mkval(T_ARR, (uint64_t)obj_off), (jsoff_t)del_idx); 10669 - return js_true; 10670 - } 10671 - } 10680 + if (is_nonconfig_prop(js, prop_off)) { 10681 + if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "cannot delete non-configurable property"); 10682 + return js_false; 10683 + } 10672 10684 10673 - jsoff_t prop_off = lkp(js, obj, key_str, len); 10674 - if (prop_off == 0) { 10675 - try_dynamic_deleter(js, obj, key_str, len); 10676 - return js_true; 10677 - } 10678 - 10679 - if (is_nonconfig_prop(js, prop_off)) { 10680 - if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "cannot delete non-configurable property"); 10681 - return js_false; 10682 - } 10685 + descriptor_entry_t *desc = lookup_descriptor(js, obj_off, key_str, len); 10686 + if (desc && !desc->configurable) { 10687 + if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "cannot delete non-configurable property"); 10688 + return js_false; 10689 + } 10683 10690 10684 - descriptor_entry_t *desc = lookup_descriptor(js, obj_off, key_str, len); 10685 - if (desc && !desc->configurable) { 10686 - if (js->flags & F_STRICT) return js_mkerr_typed(js, JS_ERR_TYPE, "cannot delete non-configurable property"); 10687 - return js_false; 10691 + jsoff_t first_prop = loadoff(js, obj_off) & ~(3U | FLAGMASK); 10692 + if (first_prop == prop_off) { 10693 + unlink_prop(js, obj_off, prop_off, 0); 10694 + return js_true; 10695 + } 10696 + for (jsoff_t prev = first_prop; prev != 0; ) { 10697 + jsoff_t next_prop = loadoff(js, prev) & ~(3U | FLAGMASK); 10698 + if (next_prop == prop_off) { 10699 + unlink_prop(js, obj_off, prop_off, prev); 10700 + return js_true; 10688 10701 } 10702 + prev = next_prop; 10703 + } 10704 + return js_true; 10705 + } 10689 10706 10690 - jsoff_t first_prop = loadoff(js, obj_off) & ~(3U | FLAGMASK); 10691 - if (first_prop == prop_off) { 10692 - unlink_prop(js, obj_off, prop_off, 0); 10693 - return js_true; 10694 - } 10695 - for (jsoff_t prev = first_prop; prev != 0; ) { 10696 - jsoff_t next_prop = loadoff(js, prev) & ~(3U | FLAGMASK); 10697 - if (next_prop == prop_off) { 10698 - unlink_prop(js, obj_off, prop_off, prev); 10699 - return js_true; 10700 - } 10701 - prev = next_prop; 10702 - } 10703 - return js_true; 10707 + if (vtype(operand) == T_PROP) { 10708 + jsoff_t prop_off = (jsoff_t)vdata(operand); 10709 + if (is_nonconfig_prop(js, prop_off)) { 10710 + if (js->flags & F_STRICT) return js_mkerr(js, "cannot delete non-configurable property"); 10711 + return js_false; 10704 10712 } 10705 10713 10706 - if (vtype(operand) == T_PROP) { 10707 - jsoff_t prop_off = (jsoff_t)vdata(operand); 10708 - if (is_nonconfig_prop(js, prop_off)) { 10709 - if (js->flags & F_STRICT) return js_mkerr(js, "cannot delete non-configurable property"); 10710 - return js_false; 10714 + for (jsval_t scope = js->scope; ; scope = upper(js, scope)) { 10715 + jsoff_t scope_off = (jsoff_t)vdata(scope); 10716 + jsoff_t first = loadoff(js, scope_off) & ~(3U | FLAGMASK); 10717 + if (first == prop_off) { 10718 + unlink_prop(js, scope_off, prop_off, 0); 10719 + return js_true; 10711 10720 } 10712 - 10713 - for (jsval_t scope = js->scope; ; scope = upper(js, scope)) { 10714 - jsoff_t scope_off = (jsoff_t)vdata(scope); 10715 - jsoff_t first = loadoff(js, scope_off) & ~(3U | FLAGMASK); 10716 - if (first == prop_off) { 10717 - unlink_prop(js, scope_off, prop_off, 0); 10721 + for (jsoff_t cur = first; cur != 0 && cur < js->brk; ) { 10722 + jsoff_t nx = loadoff(js, cur) & ~(3U | FLAGMASK); 10723 + if (nx == prop_off) { 10724 + unlink_prop(js, scope_off, prop_off, cur); 10718 10725 return js_true; 10719 - } 10720 - for (jsoff_t cur = first; cur != 0 && cur < js->brk; ) { 10721 - jsoff_t nx = loadoff(js, cur) & ~(3U | FLAGMASK); 10722 - if (nx == prop_off) { 10723 - unlink_prop(js, scope_off, prop_off, cur); 10724 - return js_true; 10725 - } cur = nx; 10726 - } if (vdata(scope) == 0) break; 10727 - } return js_true; 10726 + } cur = nx; 10727 + } if (vdata(scope) == 0) break; 10728 10728 } return js_true; 10729 + } return js_true; 10730 + } 10731 + 10732 + static jsval_t js_unary(struct js *js) { 10733 + uint8_t tok = next(js); 10734 + 10735 + static const void *dispatch[] = { 10736 + [TOK_NEW] = &&do_new, 10737 + [TOK_DELETE] = &&do_delete, 10738 + [TOK_AWAIT] = &&do_await, 10739 + [TOK_POSTINC] = &&do_prefix_inc, 10740 + [TOK_POSTDEC] = &&do_prefix_inc, 10741 + [TOK_NOT] = &&do_unary_op, 10742 + [TOK_TILDA] = &&do_unary_op, 10743 + [TOK_TYPEOF] = &&do_typeof, 10744 + [TOK_VOID] = &&do_unary_op, 10745 + [TOK_MINUS] = &&do_unary_op, 10746 + [TOK_PLUS] = &&do_unary_op, 10747 + }; 10748 + 10749 + if (tok < sizeof(dispatch)/sizeof(dispatch[0]) && dispatch[tok]) { 10750 + goto *dispatch[tok]; 10729 10751 } 10752 + return js_postfix(js); 10753 + 10754 + do_new: return js_unary_new(js); 10755 + do_delete: return js_unary_delete(js); 10730 10756 10731 10757 do_await: { 10732 10758 js->consumed = 1; ··· 10975 11001 jsoff_t param_len = codereflen(res); 10976 11002 js->consumed = 1; 10977 11003 10978 - char param_buf[256]; 10979 - if (param_len + 3 > sizeof(param_buf)) return js_mkerr(js, "param too long"); 11004 + char *param_buf = (char *)malloc(param_len + 3); 11005 + if (!param_buf) return js_mkerr(js, "oom"); 10980 11006 param_buf[0] = '('; 10981 11007 memcpy(param_buf + 1, &js->code[param_start], param_len); 10982 11008 param_buf[param_len + 1] = ')'; ··· 10995 11021 body_result = js_assignment(js); 10996 11022 if (is_err(body_result)) { 10997 11023 js->flags = flags; 11024 + free(param_buf); 10998 11025 return body_result; 10999 11026 } 11000 11027 } else { ··· 11004 11031 body_result = js_block(js, false); 11005 11032 if (is_err(body_result)) { 11006 11033 js->flags = flags; 11034 + free(param_buf); 11007 11035 return body_result; 11008 11036 } 11009 11037 if (js->tok == TOK_RBRACE && js->consumed) { ··· 11024 11052 size_t fn_len = params_len + body_len; 11025 11053 11026 11054 char *fn_str = (char *) malloc(fn_len + 1); 11027 - if (!fn_str) return js_mkerr(js, "oom"); 11055 + if (!fn_str) { free(param_buf); return js_mkerr(js, "oom"); } 11028 11056 11029 11057 memcpy(fn_str, param_buf, params_len); 11030 11058 memcpy(fn_str + params_len, &js->code[body_start], body_len); 11059 + free(param_buf); 11031 11060 11032 11061 jsval_t func_obj = mkobj(js, 0); 11033 11062 if (is_err(func_obj)) { free(fn_str); return func_obj; }
+2 -7
tests/repro_bouncer_collectdecl.js
··· 39 39 const n = Number(process.argv[2] || 5000); 40 40 const xs = mkList(n); 41 41 42 - let badOverflow = false; 43 42 try { 44 43 collectBad(xs); 45 - } catch (_) { 46 - badOverflow = true; 47 - } 48 - 49 - if (!badOverflow) { 50 - console.log('FAIL: expected collectBad to overflow'); 44 + } catch { 45 + console.log('FAIL: collectBad should not overflow'); 51 46 process.exit(1); 52 47 } 53 48