History

Add gcc attribute cleanup support

The major difficulty was to handle cleanup when a goto happen to do so, I've had a "ScopeTracker" struct. I can't use local_scope because that would not work with code like below as local_scope would be at the same level: { char * __attribute__ ((cleanup(clean_function))) str = "hej"; goto next; } { next: }

matthias committed 7 years ago

Commit 0d91ba71 parent f6be0d44 files · +278 −30Browse files

Unified · Split

4 files
  1. tcc.h +21 −10
  2. tccgen.c +254 −20
  3. tccpp.c +1 −0
  4. tcctok.h +2 −0
tcc.h+21−10
@@ -456,15 +456,9 @@ struct FuncAttr { · 455 unmodified lines
456 func_args : 8; /* PE __stdcall args */456 func_args : 8; /* PE __stdcall args */
457};457};
458 458
459/* GNUC attribute definition */459typedef struct ScopeTacker {
460typedef struct AttributeDef {460 struct ScopeTacker *prev;
461 struct SymAttr a;461} ScopeTacker;
462 struct FuncAttr f;
463 struct Section *section;
464 int alias_target; /* token */
465 int asm_label; /* associated asm label */
466 char attr_mode; /* __attribute__((__mode__(...))) */
467} AttributeDef;
468 462
469/* symbol management */463/* symbol management */
470typedef struct Sym {464typedef struct Sym {
@@ -476,7 +470,10 @@ typedef struct Sym { · 5 unmodified lines
476 int c; /* associated number or Elf symbol index */470 int c; /* associated number or Elf symbol index */
477 union {471 union {
478 int sym_scope; /* scope level for locals */472 int sym_scope; /* scope level for locals */
479 int jnext; /* next jump label */473 struct {
474 ScopeTacker *scope;
475 int jnext; /* next jump label */
476 };
480 struct FuncAttr f; /* function attributes */477 struct FuncAttr f; /* function attributes */
481 int auxtype; /* bitfield access type */478 int auxtype; /* bitfield access type */
482 };479 };
@@ -590,6 +587,18 @@ typedef struct TokenString { · 107 unmodified lines
590 char alloc;587 char alloc;
591} TokenString;588} TokenString;
592 589
590/* GNUC attribute definition */
591typedef struct AttributeDef {
592 struct SymAttr a;
593 struct FuncAttr f;
594 struct Section *section;
595 Sym *cleanup_func;
596 int should_remember;
597 int alias_target; /* token */
598 int asm_label; /* associated asm label */
599 char attr_mode; /* __attribute__((__mode__(...))) */
600} AttributeDef;
601
593/* inline functions */602/* inline functions */
594typedef struct InlineFunc {603typedef struct InlineFunc {
595 TokenString *func_str;604 TokenString *func_str;
@@ -1279,6 +1288,8 @@ ST_DATA Sym *sym_free_first; · 683 unmodified lines
1279ST_DATA void **sym_pools;1288ST_DATA void **sym_pools;
1280ST_DATA int nb_sym_pools;1289ST_DATA int nb_sym_pools;
1281 1290
1291ST_DATA ScopeTacker *scope_tracker;
1292
1282ST_DATA Sym *global_stack;1293ST_DATA Sym *global_stack;
1283ST_DATA Sym *local_stack;1294ST_DATA Sym *local_stack;
1284ST_DATA Sym *local_label_stack;1295ST_DATA Sym *local_label_stack;
tccgen.c+254−20
@@ -38,7 +38,13 @@ ST_DATA Sym *local_stack; · 37 unmodified lines
38ST_DATA Sym *define_stack;38ST_DATA Sym *define_stack;
39ST_DATA Sym *global_label_stack;39ST_DATA Sym *global_label_stack;
40ST_DATA Sym *local_label_stack;40ST_DATA Sym *local_label_stack;
41
41static int local_scope;42static int local_scope;
43#define SCOPE_TCK_STORE_SIZE 1024
44ST_DATA ScopeTacker *scope_tracker;
45static ScopeTacker scope_tck_store[SCOPE_TCK_STORE_SIZE];
46static int scope_tck_idx;
47
42static int in_sizeof;48static int in_sizeof;
43static int section_sym;49static 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
80short nb_temp_local_vars;87short nb_temp_local_vars;
88static struct cleanup {
89 ScopeTacker *scope;
90 struct {
91 Sym *var;
92 Sym *func;
93 } *syms;
94 int nb_cleanup;
95} *cleanup_info;
96
97static struct cleanup **cleanup_info_store;
98static int cleanup_idx;
99
100static struct CleanupGoto {
101 Sym *s;
102 ScopeTacker *scope;
103 int jnext;
104 int is_valide;
105} **cleanup_goto_info;
106
107static int last_cleanup_goto;
108
81/* ------------------------------------------------------------------------- */109/* ------------------------------------------------------------------------- */
82 110
83static void gen_cast(CType *type);111static void gen_cast(CType *type);
@@ -108,6 +136,57 @@ static void gv_dup(void); · 24 unmodified lines
108static int get_temp_local_var(int size,int align);136static int get_temp_local_var(int size,int align);
109static void clear_temp_local_var_list();137static void clear_temp_local_var_list();
110 138
139static 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
155static void decr_local_scope(void)
156{
157 if (scope_tracker)
158 scope_tracker = scope_tracker->prev;
159 --local_scope;
160}
161
162static 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
181int 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
111ST_INLN int is_float(int t)190ST_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 declarators4643 /* 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
4793static 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
4823static 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
4834static 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
4695ST_FUNC void unary(void)4846ST_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 the6305 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 turn6306 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 else6329 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 else6533 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#endif7298#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 */
tccpp.c+1−0
@@ -1367,6 +1367,7 @@ ST_FUNC Sym *label_push(Sym **ptop, int v, int flags) · 1366 unmodified lines
1367 Sym *s, **ps;1367 Sym *s, **ps;
1368 s = sym_push2(ptop, v, 0, 0);1368 s = sym_push2(ptop, v, 0, 0);
1369 s->r = flags;1369 s->r = flags;
1370 s->scope = scope_tracker;
1370 ps = &table_ident[v - TOK_IDENT]->sym_label;1371 ps = &table_ident[v - TOK_IDENT]->sym_label;
1371 if (ptop == &global_label_stack) {1372 if (ptop == &global_label_stack) {
1372 /* modify the top most local identifier, so that1373 /* modify the top most local identifier, so that
tcctok.h+2−0
@@ -123,6 +123,8 @@ · 122 unmodified lines
123 DEF(TOK_FASTCALL3, "__fastcall__")123 DEF(TOK_FASTCALL3, "__fastcall__")
124 DEF(TOK_REGPARM1, "regparm")124 DEF(TOK_REGPARM1, "regparm")
125 DEF(TOK_REGPARM2, "__regparm__")125 DEF(TOK_REGPARM2, "__regparm__")
126 DEF(TOK_CLEANUP1, "cleanup")
127 DEF(TOK_CLEANUP2, "__cleanup__")
126 128
127 DEF(TOK_MODE, "__mode__")129 DEF(TOK_MODE, "__mode__")
128 DEF(TOK_MODE_QI, "__QI__")130 DEF(TOK_MODE_QI, "__QI__")

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t