| @@ -39,15 +39,10 @@ ST_DATA Sym *define_stack; · 38 unmodified lines |
| 39 | 39 | ST_DATA Sym *global_label_stack; |
| 40 | 40 | ST_DATA Sym *local_label_stack; |
| 41 | 41 | |
| 42 | | −static int local_scope; |
| 43 | | −#define SCOPE_TCK_STORE_SIZE 512 |
| 44 | | −ST_DATA ScopeTacker *scope_tracker; |
| 45 | | −static ScopeTacker scope_tck_store[SCOPE_TCK_STORE_SIZE]; |
| 46 | | −static int scope_tck_store_len; |
| 47 | | − |
| 48 | | −static ScopeTacker **scope_tck_2nd_store; |
| 49 | | −static int scope_tck_2nd_store_len; |
| 42 | +static Sym *all_cleanups, *current_cleanups, *pending_gotos; |
| 43 | +static int ncleanups; |
| 50 | 44 | |
| 45 | +static int local_scope; |
| 51 | 46 | static int in_sizeof; |
| 52 | 47 | static int section_sym; |
| 53 | 48 | |
| @@ -86,28 +81,7 @@ ST_DATA struct temp_local_variable { · 32 unmodified lines |
| 86 | 81 | short size; |
| 87 | 82 | short align; |
| 88 | 83 | } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; |
| 89 | | − |
| 90 | 84 | short nb_temp_local_vars; |
| 91 | | −static struct cleanup { |
| 92 | | − ScopeTacker *scope; |
| 93 | | − struct { |
| 94 | | − Sym *var; |
| 95 | | − Sym *func; |
| 96 | | − } *syms; |
| 97 | | − int nb_cleanup; |
| 98 | | −} *cleanup_info; |
| 99 | | − |
| 100 | | −static struct cleanup **cleanup_info_store; |
| 101 | | −static int cleanup_idx; |
| 102 | | − |
| 103 | | −static struct CleanupGoto { |
| 104 | | − Sym *s; |
| 105 | | − ScopeTacker *scope; |
| 106 | | − int jnext; |
| 107 | | − int is_valide; |
| 108 | | −} **cleanup_goto_info; |
| 109 | | − |
| 110 | | −static int last_cleanup_goto; |
| 111 | 85 | |
| 112 | 86 | /* ------------------------------------------------------------------------- */ |
| 113 | 87 | |
| @@ -141,59 +115,20 @@ static void clear_temp_local_var_list(); · 27 unmodified lines |
| 141 | 115 | |
| 142 | 116 | static void incr_local_scope(void) |
| 143 | 117 | { |
| 144 | | − ScopeTacker *tmp = scope_tracker; |
| 145 | | − |
| 146 | 118 | ++local_scope; |
| 147 | | − if (scope_tck_store_len >= SCOPE_TCK_STORE_SIZE) { |
| 148 | | − scope_tracker = tcc_malloc(sizeof(ScopeTacker)); |
| 149 | | − dynarray_add(&scope_tck_2nd_store, |
| 150 | | − &scope_tck_2nd_store_len, scope_tracker); |
| 151 | | − } else { |
| 152 | | − scope_tracker = &scope_tck_store[scope_tck_store_len]; |
| 153 | | − ++scope_tck_store_len; |
| 154 | | − } |
| 155 | | − scope_tracker->prev = tmp; |
| 156 | 119 | } |
| 157 | 120 | |
| 158 | 121 | static void decr_local_scope(void) |
| 159 | 122 | { |
| 160 | | − if (scope_tracker) |
| 161 | | − scope_tracker = scope_tracker->prev; |
| 162 | 123 | --local_scope; |
| 163 | 124 | } |
| 164 | 125 | |
| 165 | 126 | static void reset_local_scope(void) |
| 166 | 127 | { |
| 167 | | − if (cleanup_info) { |
| 168 | | − int i = 0; |
| 169 | | − |
| 170 | | − for (; i < cleanup_idx; ++i) { |
| 171 | | − cleanup_info = cleanup_info_store[i]; |
| 172 | | − tcc_free(cleanup_info->syms); |
| 173 | | − tcc_free(cleanup_info); |
| 174 | | − } |
| 175 | | − cleanup_info = NULL; |
| 176 | | − cleanup_idx = 0; |
| 177 | | − tcc_free(cleanup_info_store); |
| 178 | | − cleanup_info_store = NULL; |
| 179 | | − dynarray_reset(&cleanup_goto_info, &last_cleanup_goto); |
| 180 | | − } |
| 181 | | − scope_tracker = NULL; |
| 128 | + if (current_cleanups) |
| 129 | + tcc_error("ICE current_cleanups"); |
| 130 | + sym_pop(&all_cleanups, NULL, 0); |
| 182 | 131 | local_scope = 0; |
| 183 | | − scope_tck_store_len = 0; |
| 184 | | − if (scope_tck_2nd_store_len) |
| 185 | | − dynarray_reset(&scope_tck_2nd_store, &scope_tck_2nd_store_len); |
| 186 | | −} |
| 187 | | − |
| 188 | | −int is_scope_a_parent_of(ScopeTacker *parent, ScopeTacker *child) |
| 189 | | −{ |
| 190 | | − ScopeTacker *cur = parent->prev; |
| 191 | | − |
| 192 | | − for (; cur; cur = cur->prev) { |
| 193 | | − if (cur == child) |
| 194 | | − return 1; |
| 195 | | − } |
| 196 | | − return 0; |
| 197 | 132 | } |
| 198 | 133 | |
| 199 | 134 | ST_INLN int is_float(int t) |
| @@ -4646,8 +4581,6 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) · 4446 unmodified lines |
| 4646 | 4581 | ret = pointed_type(type); |
| 4647 | 4582 | } |
| 4648 | 4583 | |
| 4649 | | − if (ad->cleanup_func) |
| 4650 | | − ad->should_remember = 1; |
| 4651 | 4584 | if (tok == '(') { |
| 4652 | 4585 | /* This is possibly a parameter type list for abstract declarators |
| 4653 | 4586 | ('int ()'), use post_type for testing this. */ |
| @@ -4799,67 +4732,43 @@ static void parse_builtin_params(int nc, const char *args) · 145 unmodified lines |
| 4799 | 4732 | nocode_wanted--; |
| 4800 | 4733 | } |
| 4801 | 4734 | |
| 4802 | | −static void try_call_scope_cleanup(ScopeTacker *scope) |
| 4735 | +static void try_call_scope_cleanup(Sym *stop) |
| 4803 | 4736 | { |
| 4804 | | − int i; |
| 4805 | | − |
| 4806 | | − if (!cleanup_info) |
| 4807 | | − return; |
| 4737 | + Sym *cls = current_cleanups; |
| 4808 | 4738 | |
| 4809 | | − if (cleanup_info->scope != scope) { |
| 4810 | | − int i = 0; |
| 4811 | | − |
| 4812 | | − for (; i < cleanup_idx; ++i) { |
| 4813 | | − cleanup_info = cleanup_info_store[i]; |
| 4814 | | − if (cleanup_info->scope == scope) |
| 4815 | | − goto found; |
| 4816 | | − } |
| 4817 | | − return; |
| 4818 | | − } |
| 4819 | | − found: |
| 4820 | | − for (i = cleanup_info->nb_cleanup - 1; i >= 0; --i) { |
| 4821 | | − Sym *fs = cleanup_info->syms[i].func; |
| 4822 | | − Sym *vs = cleanup_info->syms[i].var; |
| 4739 | + for (; cls != stop; cls = cls->ncl) { |
| 4740 | + Sym *fs = cls->next; |
| 4741 | + Sym *vs = cls->prev_tok; |
| 4823 | 4742 | |
| 4824 | 4743 | vpushsym(&fs->type, fs); |
| 4825 | | − if (is_float(vs->type.t)) { |
| 4826 | | − vs->type.t = VT_INT; |
| 4827 | | − } |
| 4828 | 4744 | vset(&vs->type, vs->r, vs->c); |
| 4829 | 4745 | vtop->sym = vs; |
| 4746 | + mk_pointer(&vtop->type); |
| 4830 | 4747 | gaddrof(); |
| 4831 | | − gfunc_param_typed(fs, vs); |
| 4832 | 4748 | gfunc_call(1); |
| 4833 | 4749 | } |
| 4834 | 4750 | } |
| 4835 | 4751 | |
| 4836 | | −static void try_call_cleanup_goto(ScopeTacker *dest_scope) |
| 4752 | +static void try_call_cleanup_goto(Sym *cleanupstate) |
| 4837 | 4753 | { |
| 4838 | | − ScopeTacker *cur_scope_tracker; |
| 4754 | + Sym *oc, *cc; |
| 4755 | + int ocd, ccd; |
| 4839 | 4756 | |
| 4840 | | − if (!cleanup_info) |
| 4757 | + if (!current_cleanups) |
| 4841 | 4758 | return; |
| 4842 | | − for (cur_scope_tracker = scope_tracker; |
| 4843 | | − cur_scope_tracker && cur_scope_tracker != dest_scope; |
| 4844 | | − cur_scope_tracker = cur_scope_tracker->prev) { |
| 4845 | | − try_call_scope_cleanup(cur_scope_tracker); |
| 4846 | | − } |
| 4847 | | −} |
| 4848 | 4759 | |
| 4849 | | −static void try_call_all_cleanup(void) |
| 4850 | | −{ |
| 4851 | | − ScopeTacker *cur_scope_tracker; |
| 4760 | + /* search NCA of both cleanup chains given parents and initial depth */ |
| 4761 | + ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0; |
| 4762 | + for (ccd = ncleanups, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl) |
| 4763 | + ; |
| 4764 | + for (cc = current_cleanups; ccd > ocd; --ccd, cc = cc->ncl) |
| 4765 | + ; |
| 4766 | + for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd) |
| 4767 | + ; |
| 4852 | 4768 | |
| 4853 | | − if (!cleanup_info) |
| 4854 | | − return; |
| 4855 | | − for (cur_scope_tracker = scope_tracker; |
| 4856 | | − cur_scope_tracker; |
| 4857 | | − cur_scope_tracker = cur_scope_tracker->prev) { |
| 4858 | | − try_call_scope_cleanup(cur_scope_tracker); |
| 4859 | | − } |
| 4769 | + try_call_scope_cleanup(cc); |
| 4860 | 4770 | } |
| 4861 | 4771 | |
| 4862 | | − |
| 4863 | 4772 | ST_FUNC void unary(void) |
| 4864 | 4773 | { |
| 4865 | 4774 | int n, t, align, size, r, sizeof_caller; |
| @@ -6252,14 +6161,16 @@ static void block(int *bsym, int *csym, int is_expr) · 1386 unmodified lines |
| 6252 | 6161 | gsym(a); |
| 6253 | 6162 | gsym_addr(b, d); |
| 6254 | 6163 | } else if (tok == '{') { |
| 6255 | | − Sym *llabel; |
| 6164 | + Sym *llabel, *lcleanup; |
| 6256 | 6165 | int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; |
| 6166 | + int lncleanups = ncleanups; |
| 6257 | 6167 | |
| 6258 | 6168 | next(); |
| 6259 | 6169 | /* record local declaration stack position */ |
| 6260 | 6170 | s = local_stack; |
| 6261 | 6171 | llabel = local_label_stack; |
| 6262 | | − incr_local_scope(); |
| 6172 | + lcleanup = current_cleanups; |
| 6173 | + incr_local_scope(); |
| 6263 | 6174 | |
| 6264 | 6175 | /* handle local labels declarations */ |
| 6265 | 6176 | while (tok == TOK_LABEL) { |
| @@ -6289,32 +6200,35 @@ static void block(int *bsym, int *csym, int is_expr) · 23 unmodified lines |
| 6289 | 6200 | } |
| 6290 | 6201 | } |
| 6291 | 6202 | |
| 6292 | | − if (cleanup_info) { |
| 6293 | | − int jmp = 0; |
| 6294 | | − int i; |
| 6295 | | − |
| 6296 | | − jmp = gjmp(jmp); |
| 6297 | | − |
| 6298 | | − for (i = 0; i < last_cleanup_goto; ++i) { |
| 6299 | | − struct CleanupGoto *cur = cleanup_goto_info[i]; |
| 6300 | | − |
| 6301 | | − if (!cur->is_valide) |
| 6302 | | − continue; |
| 6303 | | − if (scope_tracker == cur->scope || |
| 6304 | | − is_scope_a_parent_of(cur->scope, scope_tracker)) { |
| 6305 | | − gsym(cur->jnext); |
| 6306 | | − try_call_scope_cleanup(scope_tracker); |
| 6307 | | − cur->jnext = 0; |
| 6308 | | − cur->jnext = gjmp(cur->jnext); |
| 6309 | | − } |
| 6310 | | − } |
| 6311 | | − |
| 6312 | | − gsym(jmp); |
| 6313 | | − if (!nocode_wanted) { |
| 6314 | | − try_call_scope_cleanup(scope_tracker); |
| 6315 | | − } |
| 6316 | | − } |
| 6203 | + if (current_cleanups != lcleanup) { |
| 6204 | + int jmp = 0; |
| 6205 | + Sym *g, **pg; |
| 6206 | + |
| 6207 | + for (pg = &pending_gotos; (g = *pg) && g->c > lncleanups;) |
| 6208 | + if (g->prev_tok->r & LABEL_FORWARD) { |
| 6209 | + Sym *pcl = g->next; |
| 6210 | + if (!jmp) |
| 6211 | + jmp = gjmp(0); |
| 6212 | + gsym(pcl->jnext); |
| 6213 | + try_call_scope_cleanup(lcleanup); |
| 6214 | + pcl->jnext = gjmp(0); |
| 6215 | + if (!lncleanups) |
| 6216 | + goto remove_pending; |
| 6217 | + g->c = lncleanups; |
| 6218 | + pg = &g->prev; |
| 6219 | + } else { |
| 6220 | + remove_pending: |
| 6221 | + *pg = g->prev; |
| 6222 | + sym_free(g); |
| 6223 | + } |
| 6224 | + gsym(jmp); |
| 6225 | + if (!nocode_wanted) { |
| 6226 | + try_call_scope_cleanup(lcleanup); |
| 6227 | + } |
| 6228 | + } |
| 6317 | 6229 | |
| 6230 | + current_cleanups = lcleanup; |
| 6231 | + ncleanups = lncleanups; |
| 6318 | 6232 | /* pop locally defined labels */ |
| 6319 | 6233 | label_pop(&local_label_stack, llabel, is_expr); |
| 6320 | 6234 | /* pop locally defined symbols */ |
| @@ -6334,20 +6248,20 @@ static void block(int *bsym, int *csym, int is_expr) · 13 unmodified lines |
| 6334 | 6248 | vla_sp_restore(); |
| 6335 | 6249 | } |
| 6336 | 6250 | vlas_in_scope = saved_vlas_in_scope; |
| 6337 | | − |
| 6251 | + |
| 6338 | 6252 | next(); |
| 6339 | 6253 | } else if (tok == TOK_RETURN) { |
| 6340 | 6254 | next(); |
| 6341 | 6255 | if (tok != ';') { |
| 6342 | 6256 | gexpr(); |
| 6343 | 6257 | gen_assign_cast(&func_vt); |
| 6344 | | − try_call_all_cleanup(); |
| 6258 | + try_call_scope_cleanup(NULL); |
| 6345 | 6259 | if ((func_vt.t & VT_BTYPE) == VT_VOID) |
| 6346 | 6260 | vtop--; |
| 6347 | 6261 | else |
| 6348 | 6262 | gfunc_return(&func_vt); |
| 6349 | 6263 | } else { |
| 6350 | | − try_call_all_cleanup(); |
| 6264 | + try_call_scope_cleanup(NULL); |
| 6351 | 6265 | } |
| 6352 | 6266 | skip(';'); |
| 6353 | 6267 | /* jump unless last stmt in top-level block */ |
| @@ -6518,39 +6432,26 @@ static void block(int *bsym, int *csym, int is_expr) · 164 unmodified lines |
| 6518 | 6432 | ggoto(); |
| 6519 | 6433 | } else if (tok >= TOK_UIDENT) { |
| 6520 | 6434 | s = label_find(tok); |
| 6521 | | − if (!s || s->jnext == -1) { |
| 6522 | | − /* put forward definition if needed */ |
| 6523 | | − if (!s) |
| 6524 | | − s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
| 6525 | | − if (cleanup_info) { |
| 6526 | | − struct CleanupGoto *cur = |
| 6527 | | − tcc_malloc(sizeof(struct CleanupGoto)); |
| 6528 | | − |
| 6529 | | − cur->s = s; |
| 6530 | | − cur->is_valide = 1; |
| 6531 | | − s->jnext = -1; |
| 6532 | | − cur->jnext = 0; |
| 6533 | | − cur->scope = scope_tracker; |
| 6534 | | − cur->jnext = gjmp(cur->jnext); |
| 6535 | | − dynarray_add(&cleanup_goto_info, &last_cleanup_goto, cur); |
| 6536 | | − vla_sp_restore_root(); |
| 6537 | | − goto out_goto; |
| 6538 | | − } |
| 6539 | | − } else { |
| 6540 | | − if (cleanup_info && is_scope_a_parent_of(scope_tracker, |
| 6541 | | − s->scope)) |
| 6542 | | − try_call_cleanup_goto(s->scope); |
| 6543 | | − |
| 6544 | | − if (s->r == LABEL_DECLARED) |
| 6545 | | − s->r = LABEL_FORWARD; |
| 6546 | | − } |
| 6435 | + /* put forward definition if needed */ |
| 6436 | + if (!s) |
| 6437 | + s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
| 6438 | + else if (s->r == LABEL_DECLARED) |
| 6439 | + s->r = LABEL_FORWARD; |
| 6547 | 6440 | |
| 6548 | 6441 | vla_sp_restore_root(); |
| 6549 | | − if (s->r & LABEL_FORWARD) |
| 6442 | + if (s->r & LABEL_FORWARD) { |
| 6443 | + /* start new goto chain for cleanups, linked via label->next */ |
| 6444 | + if (current_cleanups) { |
| 6445 | + sym_push2(&pending_gotos, SYM_FIELD, 0, ncleanups); |
| 6446 | + pending_gotos->prev_tok = s; |
| 6447 | + s = sym_push2(&s->next, SYM_FIELD, 0, 0); |
| 6448 | + pending_gotos->next = s; |
| 6449 | + } |
| 6550 | 6450 | s->jnext = gjmp(s->jnext); |
| 6551 | | − else |
| 6451 | + } else { |
| 6452 | + try_call_cleanup_goto(s->cleanupstate); |
| 6552 | 6453 | gjmp_addr(s->jnext); |
| 6553 | | − out_goto: |
| 6454 | + } |
| 6554 | 6455 | next(); |
| 6555 | 6456 | } else { |
| 6556 | 6457 | expect("label identifier"); |
| @@ -6565,26 +6466,21 @@ static void block(int *bsym, int *csym, int is_expr) · 8 unmodified lines |
| 6565 | 6466 | next(); |
| 6566 | 6467 | s = label_find(b); |
| 6567 | 6468 | if (s) { |
| 6568 | | − int is_gen = 0; |
| 6569 | | − int i; |
| 6570 | | − |
| 6571 | 6469 | if (s->r == LABEL_DEFINED) |
| 6572 | 6470 | tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
| 6573 | | − for (i = 0; i < last_cleanup_goto; ++i) { |
| 6574 | | − struct CleanupGoto *cur = cleanup_goto_info[i]; |
| 6575 | | − if (cur->s == s) { |
| 6576 | | − cur->is_valide = 0; |
| 6577 | | − gsym(cur->jnext); |
| 6578 | | − is_gen = 1; |
| 6579 | | − } |
| 6580 | | − } |
| 6581 | 6471 | s->r = LABEL_DEFINED; |
| 6582 | | − if (!is_gen) |
| 6583 | | − gsym(s->jnext); |
| 6472 | + if (s->next) { |
| 6473 | + Sym *pcl; /* pending cleanup goto */ |
| 6474 | + for (pcl = s->next; pcl; pcl = pcl->prev) |
| 6475 | + gsym(pcl->jnext); |
| 6476 | + sym_pop(&s->next, NULL, 0); |
| 6477 | + } else |
| 6478 | + gsym(s->jnext); |
| 6584 | 6479 | } else { |
| 6585 | 6480 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
| 6586 | 6481 | } |
| 6587 | 6482 | s->jnext = ind; |
| 6483 | + s->cleanupstate = current_cleanups; |
| 6588 | 6484 | vla_sp_restore(); |
| 6589 | 6485 | /* we accept this, but it is a mistake */ |
| 6590 | 6486 | block_after_label: |
| @@ -7317,25 +7213,11 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 726 unmodified lines |
| 7317 | 7213 | #endif |
| 7318 | 7214 | sym = sym_push(v, type, r, addr); |
| 7319 | 7215 | if (ad->cleanup_func) { |
| 7320 | | − int nb_cleanup; |
| 7321 | | − |
| 7322 | | − if (!cleanup_info || cleanup_info->scope != scope_tracker) { |
| 7323 | | − cleanup_info = tcc_malloc(sizeof(struct cleanup)); |
| 7324 | | − dynarray_add(&cleanup_info_store, &cleanup_idx, |
| 7325 | | − cleanup_info); |
| 7326 | | − cleanup_info ->scope = scope_tracker; |
| 7327 | | − cleanup_info->nb_cleanup = 0; |
| 7328 | | − cleanup_info->syms = NULL; |
| 7329 | | − } |
| 7330 | | − nb_cleanup = cleanup_info->nb_cleanup + 1; |
| 7331 | | − cleanup_info->syms = tcc_realloc(cleanup_info->syms, |
| 7332 | | − nb_cleanup * |
| 7333 | | − sizeof(*cleanup_info->syms)); |
| 7334 | | − cleanup_info->syms[nb_cleanup - 1].func = ad->cleanup_func; |
| 7335 | | − cleanup_info->syms[nb_cleanup - 1].var = sym; |
| 7336 | | − cleanup_info->nb_cleanup = nb_cleanup; |
| 7337 | | − if (!ad->should_remember) |
| 7338 | | − ad->cleanup_func = NULL; |
| 7216 | + Sym *cls = sym_push2(&all_cleanups, SYM_FIELD | ++ncleanups, 0, 0); |
| 7217 | + cls->prev_tok = sym; |
| 7218 | + cls->next = ad->cleanup_func; |
| 7219 | + cls->ncl = current_cleanups; |
| 7220 | + current_cleanups = cls; |
| 7339 | 7221 | } |
| 7340 | 7222 | |
| 7341 | 7223 | sym->a = ad->a; |
| @@ -7567,10 +7449,10 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 225 unmodified lines |
| 7567 | 7449 | int v, has_init, r; |
| 7568 | 7450 | CType type, btype; |
| 7569 | 7451 | Sym *sym; |
| 7570 | | − AttributeDef ad; |
| 7452 | + AttributeDef ad, adbase; |
| 7571 | 7453 | |
| 7572 | 7454 | while (1) { |
| 7573 | | − if (!parse_btype(&btype, &ad)) { |
| 7455 | + if (!parse_btype(&btype, &adbase)) { |
| 7574 | 7456 | if (is_for_loop_init) |
| 7575 | 7457 | return 0; |
| 7576 | 7458 | /* skip redundant ';' if not in old parameter decl scope */ |
| @@ -7618,6 +7500,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 41 unmodified lines |
| 7618 | 7500 | if ((type.t & VT_ARRAY) && type.ref->c < 0) { |
| 7619 | 7501 | type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c); |
| 7620 | 7502 | } |
| 7503 | + ad = adbase; |
| 7621 | 7504 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
| 7622 | 7505 | #if 0 |
| 7623 | 7506 | { |