| @@ -38,7 +38,13 @@ ST_DATA Sym *local_stack; · 37 unmodified lines |
| 38 | ST_DATA Sym *define_stack; | 38 | ST_DATA Sym *define_stack; |
| 39 | ST_DATA Sym *global_label_stack; | 39 | ST_DATA Sym *global_label_stack; |
| 40 | ST_DATA Sym *local_label_stack; | 40 | ST_DATA Sym *local_label_stack; |
| | 41 | |
| 41 | static int local_scope; | 42 | static int local_scope; |
| | 43 | #define SCOPE_TCK_STORE_SIZE 1024 |
| | 44 | ST_DATA ScopeTacker *scope_tracker; |
| | 45 | static ScopeTacker scope_tck_store[SCOPE_TCK_STORE_SIZE]; |
| | 46 | static int scope_tck_idx; |
| | 47 | |
| 42 | static int in_sizeof; | 48 | static int in_sizeof; |
| 43 | static int section_sym; | 49 | static int section_sym; |
| 44 | | 50 | |
| @@ -77,7 +83,29 @@ ST_DATA struct temp_local_variable { · 32 unmodified lines |
| 77 | short size; | 83 | short size; |
| 78 | short align; | 84 | short align; |
| 79 | } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; | 85 | } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; |
| | 86 | |
| 80 | short nb_temp_local_vars; | 87 | short nb_temp_local_vars; |
| | 88 | static struct cleanup { |
| | 89 | ScopeTacker *scope; |
| | 90 | struct { |
| | 91 | Sym *var; |
| | 92 | Sym *func; |
| | 93 | } *syms; |
| | 94 | int nb_cleanup; |
| | 95 | } *cleanup_info; |
| | 96 | |
| | 97 | static struct cleanup **cleanup_info_store; |
| | 98 | static int cleanup_idx; |
| | 99 | |
| | 100 | static struct CleanupGoto { |
| | 101 | Sym *s; |
| | 102 | ScopeTacker *scope; |
| | 103 | int jnext; |
| | 104 | int is_valide; |
| | 105 | } **cleanup_goto_info; |
| | 106 | |
| | 107 | static int last_cleanup_goto; |
| | 108 | |
| 81 | /* ------------------------------------------------------------------------- */ | 109 | /* ------------------------------------------------------------------------- */ |
| 82 | | 110 | |
| 83 | static void gen_cast(CType *type); | 111 | static void gen_cast(CType *type); |
| @@ -108,6 +136,57 @@ static void gv_dup(void); · 24 unmodified lines |
| 108 | static int get_temp_local_var(int size,int align); | 136 | static int get_temp_local_var(int size,int align); |
| 109 | static void clear_temp_local_var_list(); | 137 | static void clear_temp_local_var_list(); |
| 110 | | 138 | |
| | 139 | static void incr_local_scope(void) |
| | 140 | { |
| | 141 | ScopeTacker *tmp = scope_tracker; |
| | 142 | |
| | 143 | ++local_scope; |
| | 144 | /* if we have more scopes that SCOPE_TCK_STORE_SIZE */ |
| | 145 | /* cleanup will not work at all, but it should be a very rare case */ |
| | 146 | /* and I don't want to add too much complexiy for handeling case */ |
| | 147 | /* that should not happen */ |
| | 148 | if (scope_tck_idx < SCOPE_TCK_STORE_SIZE) { |
| | 149 | scope_tracker = &scope_tck_store[scope_tck_idx]; |
| | 150 | scope_tracker->prev = tmp; |
| | 151 | ++scope_tck_idx; |
| | 152 | } |
| | 153 | } |
| | 154 | |
| | 155 | static void decr_local_scope(void) |
| | 156 | { |
| | 157 | if (scope_tracker) |
| | 158 | scope_tracker = scope_tracker->prev; |
| | 159 | --local_scope; |
| | 160 | } |
| | 161 | |
| | 162 | static void reset_local_scope(void) |
| | 163 | { |
| | 164 | if (cleanup_info) { |
| | 165 | for (int i = 0; i < cleanup_idx; ++i) { |
| | 166 | cleanup_info = cleanup_info_store[i]; |
| | 167 | tcc_free(cleanup_info->syms); |
| | 168 | tcc_free(cleanup_info); |
| | 169 | } |
| | 170 | cleanup_info = NULL; |
| | 171 | cleanup_idx = 0; |
| | 172 | tcc_free(cleanup_info_store); |
| | 173 | cleanup_info_store = NULL; |
| | 174 | dynarray_reset(&cleanup_goto_info, &last_cleanup_goto); |
| | 175 | } |
| | 176 | scope_tracker = NULL; |
| | 177 | local_scope = 0; |
| | 178 | scope_tck_idx = 0; |
| | 179 | } |
| | 180 | |
| | 181 | int is_scope_a_parent_of(ScopeTacker *parent, ScopeTacker *child) |
| | 182 | { |
| | 183 | for (ScopeTacker *cur = parent->prev; cur; cur = cur->prev) { |
| | 184 | if (cur == child) |
| | 185 | return 1; |
| | 186 | } |
| | 187 | return 0; |
| | 188 | } |
| | 189 | |
| 111 | ST_INLN int is_float(int t) | 190 | ST_INLN int is_float(int t) |
| 112 | { | 191 | { |
| 113 | int bt; | 192 | int bt; |
| @@ -3392,6 +3471,23 @@ redo: · 3278 unmodified lines |
| 3392 | t = tok; | 3471 | t = tok; |
| 3393 | next(); | 3472 | next(); |
| 3394 | switch(t) { | 3473 | switch(t) { |
| | 3474 | case TOK_CLEANUP1: |
| | 3475 | case TOK_CLEANUP2: |
| | 3476 | { |
| | 3477 | Sym *s; |
| | 3478 | |
| | 3479 | skip('('); |
| | 3480 | s = sym_find(tok); |
| | 3481 | if (!s) { |
| | 3482 | tcc_warning("implicit declaration of function '%s'", |
| | 3483 | get_tok_str(tok, &tokc)); |
| | 3484 | s = external_global_sym(tok, &func_old_type, 0); |
| | 3485 | } |
| | 3486 | ad->cleanup_func = s; |
| | 3487 | next(); |
| | 3488 | skip(')'); |
| | 3489 | break; |
| | 3490 | } |
| 3395 | case TOK_SECTION1: | 3491 | case TOK_SECTION1: |
| 3396 | case TOK_SECTION2: | 3492 | case TOK_SECTION2: |
| 3397 | skip('('); | 3493 | skip('('); |
| @@ -4541,6 +4637,8 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) · 1143 unmodified lines |
| 4541 | ret = pointed_type(type); | 4637 | ret = pointed_type(type); |
| 4542 | } | 4638 | } |
| 4543 | | 4639 | |
| | 4640 | if (ad->cleanup_func) |
| | 4641 | ad->should_remember = 1; |
| 4544 | if (tok == '(') { | 4642 | if (tok == '(') { |
| 4545 | /* This is possibly a parameter type list for abstract declarators | 4643 | /* This is possibly a parameter type list for abstract declarators |
| 4546 | ('int ()'), use post_type for testing this. */ | 4644 | ('int ()'), use post_type for testing this. */ |
| @@ -4692,6 +4790,59 @@ static void parse_builtin_params(int nc, const char *args) · 145 unmodified lines |
| 4692 | nocode_wanted--; | 4790 | nocode_wanted--; |
| 4693 | } | 4791 | } |
| 4694 | | 4792 | |
| | 4793 | static void try_call_scope_cleanup(ScopeTacker *scope) |
| | 4794 | { |
| | 4795 | if (!cleanup_info) |
| | 4796 | return; |
| | 4797 | |
| | 4798 | if (cleanup_info->scope != scope) { |
| | 4799 | for (int i = 0; i < cleanup_idx; ++i) { |
| | 4800 | cleanup_info = cleanup_info_store[i]; |
| | 4801 | if (cleanup_info->scope == scope) |
| | 4802 | goto found; |
| | 4803 | } |
| | 4804 | return; |
| | 4805 | } |
| | 4806 | found: |
| | 4807 | for (int i = cleanup_info->nb_cleanup - 1; i >= 0; --i) { |
| | 4808 | Sym *fs = cleanup_info->syms[i].func; |
| | 4809 | Sym *vs = cleanup_info->syms[i].var; |
| | 4810 | |
| | 4811 | vpushsym(&fs->type, fs); |
| | 4812 | if (is_float(vs->type.t)) { |
| | 4813 | vs->type.t = VT_INT; |
| | 4814 | } |
| | 4815 | vset(&vs->type, vs->r, vs->c); |
| | 4816 | vtop->sym = vs; |
| | 4817 | gaddrof(); |
| | 4818 | gfunc_param_typed(fs, vs); |
| | 4819 | gfunc_call(1); |
| | 4820 | } |
| | 4821 | } |
| | 4822 | |
| | 4823 | static void try_call_cleanup_goto(ScopeTacker *dest_scope) |
| | 4824 | { |
| | 4825 | if (!cleanup_info) |
| | 4826 | return; |
| | 4827 | for (ScopeTacker *cur_scope_tracker = scope_tracker; |
| | 4828 | cur_scope_tracker && cur_scope_tracker != dest_scope; |
| | 4829 | cur_scope_tracker = cur_scope_tracker->prev) { |
| | 4830 | try_call_scope_cleanup(cur_scope_tracker); |
| | 4831 | } |
| | 4832 | } |
| | 4833 | |
| | 4834 | static void try_call_all_cleanup(void) |
| | 4835 | { |
| | 4836 | if (!cleanup_info) |
| | 4837 | return; |
| | 4838 | for (ScopeTacker *cur_scope_tracker = scope_tracker; |
| | 4839 | cur_scope_tracker; |
| | 4840 | cur_scope_tracker = cur_scope_tracker->prev) { |
| | 4841 | try_call_scope_cleanup(cur_scope_tracker); |
| | 4842 | } |
| | 4843 | } |
| | 4844 | |
| | 4845 | |
| 4695 | ST_FUNC void unary(void) | 4846 | ST_FUNC void unary(void) |
| 4696 | { | 4847 | { |
| 4697 | int n, t, align, size, r, sizeof_caller; | 4848 | int n, t, align, size, r, sizeof_caller; |
| @@ -6075,11 +6226,11 @@ static void block(int *bsym, int *csym, int is_expr) · 1377 unmodified lines |
| 6075 | skip(')'); | 6226 | skip(')'); |
| 6076 | a = gvtst(1, 0); | 6227 | a = gvtst(1, 0); |
| 6077 | b = 0; | 6228 | b = 0; |
| 6078 | ++local_scope; | 6229 | incr_local_scope(); |
| 6079 | saved_nocode_wanted = nocode_wanted; | 6230 | saved_nocode_wanted = nocode_wanted; |
| 6080 | block(&a, &b, 0); | 6231 | block(&a, &b, 0); |
| 6081 | nocode_wanted = saved_nocode_wanted; | 6232 | nocode_wanted = saved_nocode_wanted; |
| 6082 | --local_scope; | 6233 | decr_local_scope(); |
| 6083 | gjmp_addr(d); | 6234 | gjmp_addr(d); |
| 6084 | gsym(a); | 6235 | gsym(a); |
| 6085 | gsym_addr(b, d); | 6236 | gsym_addr(b, d); |
| @@ -6091,7 +6242,7 @@ static void block(int *bsym, int *csym, int is_expr) · 5 unmodified lines |
| 6091 | /* record local declaration stack position */ | 6242 | /* record local declaration stack position */ |
| 6092 | s = local_stack; | 6243 | s = local_stack; |
| 6093 | llabel = local_label_stack; | 6244 | llabel = local_label_stack; |
| 6094 | ++local_scope; | 6245 | incr_local_scope(); |
| 6095 | | 6246 | |
| 6096 | /* handle local labels declarations */ | 6247 | /* handle local labels declarations */ |
| 6097 | while (tok == TOK_LABEL) { | 6248 | while (tok == TOK_LABEL) { |
| @@ -6120,10 +6271,36 @@ static void block(int *bsym, int *csym, int is_expr) · 22 unmodified lines |
| 6120 | block(bsym, csym, is_expr); | 6271 | block(bsym, csym, is_expr); |
| 6121 | } | 6272 | } |
| 6122 | } | 6273 | } |
| | 6274 | |
| | 6275 | if (cleanup_info) { |
| | 6276 | int jmp = 0; |
| | 6277 | |
| | 6278 | jmp = gjmp(jmp); |
| | 6279 | |
| | 6280 | for (int i = 0; i < last_cleanup_goto; ++i) { |
| | 6281 | struct CleanupGoto *cur = cleanup_goto_info[i]; |
| | 6282 | |
| | 6283 | if (!cur->is_valide) |
| | 6284 | continue; |
| | 6285 | if (scope_tracker == cur->scope || |
| | 6286 | is_scope_a_parent_of(cur->scope, scope_tracker)) { |
| | 6287 | gsym(cur->jnext); |
| | 6288 | try_call_scope_cleanup(scope_tracker); |
| | 6289 | cur->jnext = 0; |
| | 6290 | cur->jnext = gjmp(cur->jnext); |
| | 6291 | } |
| | 6292 | } |
| | 6293 | |
| | 6294 | gsym(jmp); |
| | 6295 | if (!nocode_wanted) { |
| | 6296 | try_call_scope_cleanup(scope_tracker); |
| | 6297 | } |
| | 6298 | } |
| | 6299 | |
| 6123 | /* pop locally defined labels */ | 6300 | /* pop locally defined labels */ |
| 6124 | label_pop(&local_label_stack, llabel, is_expr); | 6301 | label_pop(&local_label_stack, llabel, is_expr); |
| 6125 | /* pop locally defined symbols */ | 6302 | /* pop locally defined symbols */ |
| 6126 | --local_scope; | 6303 | decr_local_scope(); |
| 6127 | /* In the is_expr case (a statement expression is finished here), | 6304 | /* In the is_expr case (a statement expression is finished here), |
| 6128 | vtop might refer to symbols on the local_stack. Either via the | 6305 | vtop might refer to symbols on the local_stack. Either via the |
| 6129 | type or via vtop->sym. We can't pop those nor any that in turn | 6306 | type or via vtop->sym. We can't pop those nor any that in turn |
| @@ -6146,11 +6323,14 @@ static void block(int *bsym, int *csym, int is_expr) · 16 unmodified lines |
| 6146 | if (tok != ';') { | 6323 | if (tok != ';') { |
| 6147 | gexpr(); | 6324 | gexpr(); |
| 6148 | gen_assign_cast(&func_vt); | 6325 | gen_assign_cast(&func_vt); |
| | 6326 | try_call_all_cleanup(); |
| 6149 | if ((func_vt.t & VT_BTYPE) == VT_VOID) | 6327 | if ((func_vt.t & VT_BTYPE) == VT_VOID) |
| 6150 | vtop--; | 6328 | vtop--; |
| 6151 | else | 6329 | else |
| 6152 | gfunc_return(&func_vt); | 6330 | gfunc_return(&func_vt); |
| 6153 | } | 6331 | } else { |
| | 6332 | try_call_all_cleanup(); |
| | 6333 | } |
| 6154 | skip(';'); | 6334 | skip(';'); |
| 6155 | /* jump unless last stmt in top-level block */ | 6335 | /* jump unless last stmt in top-level block */ |
| 6156 | if (tok != '}' || local_scope != 1) | 6336 | if (tok != '}' || local_scope != 1) |
| @@ -6179,7 +6359,7 @@ static void block(int *bsym, int *csym, int is_expr) · 22 unmodified lines |
| 6179 | next(); | 6359 | next(); |
| 6180 | skip('('); | 6360 | skip('('); |
| 6181 | s = local_stack; | 6361 | s = local_stack; |
| 6182 | ++local_scope; | 6362 | incr_local_scope(); |
| 6183 | if (tok != ';') { | 6363 | if (tok != ';') { |
| 6184 | /* c99 for-loop init decl? */ | 6364 | /* c99 for-loop init decl? */ |
| 6185 | if (!decl0(VT_LOCAL, 1, NULL)) { | 6365 | if (!decl0(VT_LOCAL, 1, NULL)) { |
| @@ -6215,7 +6395,7 @@ static void block(int *bsym, int *csym, int is_expr) · 29 unmodified lines |
| 6215 | gjmp_addr(c); | 6395 | gjmp_addr(c); |
| 6216 | gsym(a); | 6396 | gsym(a); |
| 6217 | gsym_addr(b, c); | 6397 | gsym_addr(b, c); |
| 6218 | --local_scope; | 6398 | decr_local_scope(); |
| 6219 | sym_pop(&local_stack, s, 0); | 6399 | sym_pop(&local_stack, s, 0); |
| 6220 | | 6400 | |
| 6221 | } else | 6401 | } else |
| @@ -6319,21 +6499,42 @@ static void block(int *bsym, int *csym, int is_expr) · 97 unmodified lines |
| 6319 | expect("pointer"); | 6499 | expect("pointer"); |
| 6320 | ggoto(); | 6500 | ggoto(); |
| 6321 | } else if (tok >= TOK_UIDENT) { | 6501 | } else if (tok >= TOK_UIDENT) { |
| 6322 | s = label_find(tok); | 6502 | s = label_find(tok); |
| 6323 | /* put forward definition if needed */ | 6503 | if (!s || s->jnext == -1) { |
| 6324 | if (!s) { | 6504 | /* put forward definition if needed */ |
| 6325 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); | 6505 | if (!s) |
| | 6506 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
| | 6507 | if (cleanup_info) { |
| | 6508 | struct CleanupGoto *cur = |
| | 6509 | tcc_malloc(sizeof(struct CleanupGoto)); |
| | 6510 | |
| | 6511 | cur->s = s; |
| | 6512 | cur->is_valide = 1; |
| | 6513 | s->jnext = -1; |
| | 6514 | cur->jnext = 0; |
| | 6515 | cur->scope = scope_tracker; |
| | 6516 | cur->jnext = gjmp(cur->jnext); |
| | 6517 | dynarray_add(&cleanup_goto_info, &last_cleanup_goto, cur); |
| | 6518 | vla_sp_restore_root(); |
| | 6519 | goto out_goto; |
| | 6520 | } |
| 6326 | } else { | 6521 | } else { |
| | 6522 | if (cleanup_info && is_scope_a_parent_of(scope_tracker, |
| | 6523 | s->scope)) |
| | 6524 | try_call_cleanup_goto(s->scope); |
| | 6525 | |
| 6327 | if (s->r == LABEL_DECLARED) | 6526 | if (s->r == LABEL_DECLARED) |
| 6328 | s->r = LABEL_FORWARD; | 6527 | s->r = LABEL_FORWARD; |
| 6329 | } | 6528 | } |
| 6330 | vla_sp_restore_root(); | 6529 | |
| | 6530 | vla_sp_restore_root(); |
| 6331 | if (s->r & LABEL_FORWARD) | 6531 | if (s->r & LABEL_FORWARD) |
| 6332 | s->jnext = gjmp(s->jnext); | 6532 | s->jnext = gjmp(s->jnext); |
| 6333 | else | 6533 | else |
| 6334 | gjmp_addr(s->jnext); | 6534 | gjmp_addr(s->jnext); |
| 6335 | next(); | 6535 | out_goto: |
| 6336 | } else { | 6536 | next(); |
| | 6537 | } else { |
| 6337 | expect("label identifier"); | 6538 | expect("label identifier"); |
| 6338 | } | 6539 | } |
| 6339 | skip(';'); | 6540 | skip(';'); |
| @@ -6346,10 +6547,21 @@ static void block(int *bsym, int *csym, int is_expr) · 6 unmodified lines |
| 6346 | next(); | 6547 | next(); |
| 6347 | s = label_find(b); | 6548 | s = label_find(b); |
| 6348 | if (s) { | 6549 | if (s) { |
| | 6550 | int is_gen = 0; |
| | 6551 | |
| 6349 | if (s->r == LABEL_DEFINED) | 6552 | if (s->r == LABEL_DEFINED) |
| 6350 | tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); | 6553 | tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
| 6351 | gsym(s->jnext); | 6554 | for (int i = 0; i < last_cleanup_goto; ++i) { |
| | 6555 | struct CleanupGoto *cur = cleanup_goto_info[i]; |
| | 6556 | if (cur->s == s) { |
| | 6557 | cur->is_valide = 0; |
| | 6558 | gsym(cur->jnext); |
| | 6559 | is_gen = 1; |
| | 6560 | } |
| | 6561 | } |
| 6352 | s->r = LABEL_DEFINED; | 6562 | s->r = LABEL_DEFINED; |
| | 6563 | if (!is_gen) |
| | 6564 | gsym(s->jnext); |
| 6353 | } else { | 6565 | } else { |
| 6354 | s = label_push(&global_label_stack, b, LABEL_DEFINED); | 6566 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
| 6355 | } | 6567 | } |
| @@ -7085,6 +7297,28 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 729 unmodified lines |
| 7085 | } | 7297 | } |
| 7086 | #endif | 7298 | #endif |
| 7087 | sym = sym_push(v, type, r, addr); | 7299 | sym = sym_push(v, type, r, addr); |
| | 7300 | if (ad->cleanup_func) { |
| | 7301 | int nb_cleanup; |
| | 7302 | |
| | 7303 | if (!cleanup_info || cleanup_info->scope != scope_tracker) { |
| | 7304 | cleanup_info = tcc_malloc(sizeof(struct cleanup)); |
| | 7305 | dynarray_add(&cleanup_info_store, &cleanup_idx, |
| | 7306 | cleanup_info); |
| | 7307 | cleanup_info ->scope = scope_tracker; |
| | 7308 | cleanup_info->nb_cleanup = 0; |
| | 7309 | cleanup_info->syms = NULL; |
| | 7310 | } |
| | 7311 | nb_cleanup = cleanup_info->nb_cleanup + 1; |
| | 7312 | cleanup_info->syms = tcc_realloc(cleanup_info->syms, |
| | 7313 | nb_cleanup * |
| | 7314 | sizeof(*cleanup_info->syms)); |
| | 7315 | cleanup_info->syms[nb_cleanup - 1].func = ad->cleanup_func; |
| | 7316 | cleanup_info->syms[nb_cleanup - 1].var = sym; |
| | 7317 | cleanup_info->nb_cleanup = nb_cleanup; |
| | 7318 | if (!ad->should_remember) |
| | 7319 | ad->cleanup_func = NULL; |
| | 7320 | } |
| | 7321 | |
| 7088 | sym->a = ad->a; | 7322 | sym->a = ad->a; |
| 7089 | } else { | 7323 | } else { |
| 7090 | /* push local reference */ | 7324 | /* push local reference */ |
| @@ -7226,7 +7460,7 @@ static void gen_function(Sym *sym) · 135 unmodified lines |
| 7226 | sym_push2(&local_stack, SYM_FIELD, 0, 0); | 7460 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
| 7227 | local_scope = 1; /* for function parameters */ | 7461 | local_scope = 1; /* for function parameters */ |
| 7228 | gfunc_prolog(&sym->type); | 7462 | gfunc_prolog(&sym->type); |
| 7229 | local_scope = 0; | 7463 | reset_local_scope(); |
| 7230 | rsym = 0; | 7464 | rsym = 0; |
| 7231 | clear_temp_local_var_list(); | 7465 | clear_temp_local_var_list(); |
| 7232 | block(NULL, NULL, 0); | 7466 | block(NULL, NULL, 0); |
| @@ -7245,7 +7479,7 @@ static void gen_function(Sym *sym) · 12 unmodified lines |
| 7245 | cur_text_section->data_offset = ind; | 7479 | cur_text_section->data_offset = ind; |
| 7246 | label_pop(&global_label_stack, NULL, 0); | 7480 | label_pop(&global_label_stack, NULL, 0); |
| 7247 | /* reset local stack */ | 7481 | /* reset local stack */ |
| 7248 | local_scope = 0; | 7482 | reset_local_scope(); |
| 7249 | sym_pop(&local_stack, NULL, 0); | 7483 | sym_pop(&local_stack, NULL, 0); |
| 7250 | /* end of function */ | 7484 | /* end of function */ |
| 7251 | /* patch symbol size */ | 7485 | /* patch symbol size */ |