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.

prevent blowing up memory with loop block scope management

+89 -8
+89 -8
src/ant.c
··· 4604 4604 static void mkscope(struct js *js) { (void)js_mkscope(js); } 4605 4605 static void delscope(struct js *js) { (void)js_delscope(js); } 4606 4606 4607 + static void scope_clear_props(struct js *js, jsval_t scope) { 4608 + jsoff_t off = (jsoff_t)vdata(scope); 4609 + jsoff_t header = loadoff(js, off); 4610 + jsoff_t parent = loadoff(js, off + sizeof(jsoff_t)); 4611 + 4612 + saveoff(js, off, (header & FLAGMASK) | T_OBJ); 4613 + saveoff(js, off + sizeof(jsoff_t), parent); 4614 + } 4615 + 4616 + static bool block_needs_scope(struct js *js) { 4617 + jsoff_t pos = js->pos, toff = js->toff, tlen = js->tlen; 4618 + uint8_t tok = js->tok, consumed = js->consumed; 4619 + bool had_newline = js->had_newline; 4620 + 4621 + bool needs = false; 4622 + int depth = 1; 4623 + js->consumed = 1; 4624 + 4625 + while (depth > 0) { 4626 + uint8_t t = next(js); 4627 + if (t == TOK_EOF) break; 4628 + if (t == TOK_LBRACE) { depth++; js->consumed = 1; continue; } 4629 + if (t == TOK_RBRACE) { depth--; js->consumed = 1; continue; } 4630 + if (depth == 1 && (t == TOK_LET || t == TOK_CONST || t == TOK_CLASS)) { needs = true; break; } 4631 + js->consumed = 1; 4632 + } 4633 + 4634 + js->pos = pos; js->toff = toff; js->tlen = tlen; 4635 + js->tok = tok; js->consumed = consumed; js->had_newline = had_newline; 4636 + 4637 + return needs; 4638 + } 4639 + 4607 4640 static inline bool push_this(jsval_t this_value) { 4608 4641 if (global_this_stack.depth >= global_this_stack.capacity) { 4609 4642 int new_capacity = global_this_stack.capacity == 0 ? 16 : global_this_stack.capacity * 2; ··· 4813 4846 4814 4847 static jsval_t js_block(struct js *js, bool create_scope) { 4815 4848 jsval_t res = js_mkundef(); 4816 - if (create_scope) mkscope(js); 4849 + bool scope_created = false; 4850 + 4851 + if (create_scope && lookahead(js) != TOK_RBRACE && block_needs_scope(js)) { 4852 + mkscope(js); 4853 + scope_created = true; 4854 + } 4817 4855 4818 4856 js->consumed = 1; 4819 4857 hoist_function_declarations(js); ··· 4829 4867 } 4830 4868 4831 4869 if (js->tok == TOK_RBRACE) js->consumed = 1; 4832 - if (create_scope) delscope(js); 4870 + if (scope_created) delscope(js); 4833 4871 4834 4872 return res; 4835 4873 } ··· 10018 10056 return res; 10019 10057 } 10020 10058 10059 + typedef struct { 10060 + bool is_block; 10061 + bool needs_scope; 10062 + jsval_t loop_scope; 10063 + } loop_block_ctx_t; 10064 + 10065 + static void loop_block_init(struct js *js, loop_block_ctx_t *ctx) { 10066 + ctx->is_block = (lookahead(js) == TOK_LBRACE); 10067 + ctx->needs_scope = false; 10068 + ctx->loop_scope = js_mkundef(); 10069 + 10070 + if (ctx->is_block && !(js->flags & F_NOEXEC)) { 10071 + jsoff_t saved_pos = js->pos; 10072 + uint8_t saved_tok = js->tok; 10073 + uint8_t saved_consumed = js->consumed; 10074 + 10075 + js->consumed = 1; 10076 + next(js); 10077 + ctx->needs_scope = block_needs_scope(js); 10078 + 10079 + js->pos = saved_pos; 10080 + js->tok = saved_tok; 10081 + js->consumed = saved_consumed; 10082 + 10083 + if (ctx->needs_scope) ctx->loop_scope = js_mkscope(js); 10084 + } 10085 + } 10086 + 10087 + static inline jsval_t loop_block_exec(struct js *js, loop_block_ctx_t *ctx) { 10088 + if (ctx->needs_scope) scope_clear_props(js, ctx->loop_scope); 10089 + return js_block_or_stmt(js); 10090 + } 10091 + 10092 + static inline void loop_block_cleanup(struct js *js, loop_block_ctx_t *ctx) { 10093 + if (ctx->needs_scope) delscope(js); 10094 + } 10095 + 10021 10096 static jsval_t js_if(struct js *js) { 10022 10097 js->consumed = 1; 10023 10098 EXPECT(TOK_LPAREN, ); ··· 10611 10686 static jsval_t js_while(struct js *js) { 10612 10687 uint8_t flags = js->flags, exe = !(flags & F_NOEXEC); 10613 10688 jsval_t res = js_mkundef(), v; 10689 + loop_block_ctx_t loop_ctx = {0}; 10614 10690 10615 10691 bool use_label_stack = label_stack && utarray_len(label_stack) > 0; 10616 10692 int marker_index = 0; ··· 10631 10707 if (!expect(js, TOK_RPAREN, &res)) goto done; 10632 10708 10633 10709 jsoff_t body_start = js->pos; 10710 + if (exe) loop_block_init(js, &loop_ctx); 10711 + 10634 10712 v = js_block_or_stmt(js); 10635 10713 if (is_err(v)) { res = v; goto done; } 10636 10714 jsoff_t body_end = js->pos; ··· 10653 10731 js->consumed = 1; 10654 10732 js->flags = (flags & ~F_NOEXEC) | F_LOOP; 10655 10733 10656 - v = js_block_or_stmt(js); 10734 + v = loop_block_exec(js, &loop_ctx); 10657 10735 if (is_err(v)) { 10658 - res = v; 10659 - break; 10736 + res = v; break; 10660 10737 } 10661 10738 10662 10739 if (label_flags & F_CONTINUE_LABEL) { ··· 10676 10753 break; 10677 10754 } 10678 10755 } 10756 + loop_block_cleanup(js, &loop_ctx); 10679 10757 } 10680 10758 10681 10759 js->pos = body_end; ··· 10705 10783 static jsval_t js_do_while(struct js *js) { 10706 10784 uint8_t flags = js->flags, exe = !(flags & F_NOEXEC); 10707 10785 jsval_t res = js_mkundef(), v; 10786 + loop_block_ctx_t loop_ctx = {0}; 10708 10787 10709 10788 bool use_label_stack = label_stack && utarray_len(label_stack) > 0; 10710 10789 int marker_index = 0; ··· 10718 10797 10719 10798 jsoff_t body_start = js->pos; 10720 10799 bool is_block = (next(js) == TOK_LBRACE); 10800 + if (exe) loop_block_init(js, &loop_ctx); 10801 + 10721 10802 js->flags |= F_NOEXEC; 10722 10803 v = js_block_or_stmt(js); 10723 10804 if (is_err(v)) { res = v; goto done; } ··· 10743 10824 js->consumed = 1; 10744 10825 js->flags = (flags & ~F_NOEXEC) | F_LOOP; 10745 10826 10746 - v = js_block_or_stmt(js); 10827 + v = loop_block_exec(js, &loop_ctx); 10747 10828 if (is_err(v)) { 10748 - res = v; 10749 - break; 10829 + res = v; break; 10750 10830 } 10751 10831 10752 10832 if (label_flags & F_CONTINUE_LABEL) { ··· 10775 10855 break; 10776 10856 } 10777 10857 } while (js_truthy(js, v)); 10858 + loop_block_cleanup(js, &loop_ctx); 10778 10859 } 10779 10860 10780 10861 js->pos = cond_end;