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
456456 func_args : 8; /* PE __stdcall args */
457457 };
458458
459−/* GNUC attribute definition */
460−typedef struct AttributeDef {
461− struct SymAttr a;
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;
459+typedef struct ScopeTacker {
460+ struct ScopeTacker *prev;
461+} ScopeTacker;
468462
469463 /* symbol management */
470464 typedef struct Sym {
@@ -476,7 +470,10 @@ typedef struct Sym { · 5 unmodified lines
476470 int c; /* associated number or Elf symbol index */
477471 union {
478472 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+ };
480477 struct FuncAttr f; /* function attributes */
481478 int auxtype; /* bitfield access type */
482479 };
@@ -590,6 +587,18 @@ typedef struct TokenString { · 107 unmodified lines
590587 char alloc;
591588 } TokenString;
592589
590+/* GNUC attribute definition */
591+typedef 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+
593602 /* inline functions */
594603 typedef struct InlineFunc {
595604 TokenString *func_str;
@@ -1279,6 +1288,8 @@ ST_DATA Sym *sym_free_first; · 683 unmodified lines
12791288 ST_DATA void **sym_pools;
12801289 ST_DATA int nb_sym_pools;
12811290
1291+ST_DATA ScopeTacker *scope_tracker;
1292+
12821293 ST_DATA Sym *global_stack;
12831294 ST_DATA Sym *local_stack;
12841295 ST_DATA Sym *local_label_stack;
tccgen.c+254−20
@@ -38,7 +38,13 @@ ST_DATA Sym *local_stack; · 37 unmodified lines
3838 ST_DATA Sym *define_stack;
3939 ST_DATA Sym *global_label_stack;
4040 ST_DATA Sym *local_label_stack;
41+
4142 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+
4248 static int in_sizeof;
4349 static int section_sym;
4450
@@ -77,7 +83,29 @@ ST_DATA struct temp_local_variable { · 32 unmodified lines
7783 short size;
7884 short align;
7985 } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
86+
8087 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+
81109 /* ------------------------------------------------------------------------- */
82110
83111 static void gen_cast(CType *type);
@@ -108,6 +136,57 @@ static void gv_dup(void); · 24 unmodified lines
108136 static int get_temp_local_var(int size,int align);
109137 static void clear_temp_local_var_list();
110138
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+
111190 ST_INLN int is_float(int t)
112191 {
113192 int bt;
@@ -3392,6 +3471,23 @@ redo: · 3278 unmodified lines
33923471 t = tok;
33933472 next();
33943473 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+ }
33953491 case TOK_SECTION1:
33963492 case TOK_SECTION2:
33973493 skip('(');
@@ -4541,6 +4637,8 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) · 1143 unmodified lines
45414637 ret = pointed_type(type);
45424638 }
45434639
4640+ if (ad->cleanup_func)
4641+ ad->should_remember = 1;
45444642 if (tok == '(') {
45454643 /* This is possibly a parameter type list for abstract declarators
45464644 ('int ()'), use post_type for testing this. */
@@ -4692,6 +4790,59 @@ static void parse_builtin_params(int nc, const char *args) · 145 unmodified lines
46924790 nocode_wanted--;
46934791 }
46944792
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+
46954846 ST_FUNC void unary(void)
46964847 {
46974848 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
60756226 skip(')');
60766227 a = gvtst(1, 0);
60776228 b = 0;
6078− ++local_scope;
6229+ incr_local_scope();
60796230 saved_nocode_wanted = nocode_wanted;
60806231 block(&a, &b, 0);
60816232 nocode_wanted = saved_nocode_wanted;
6082− --local_scope;
6233+ decr_local_scope();
60836234 gjmp_addr(d);
60846235 gsym(a);
60856236 gsym_addr(b, d);
@@ -6091,7 +6242,7 @@ static void block(int *bsym, int *csym, int is_expr) · 5 unmodified lines
60916242 /* record local declaration stack position */
60926243 s = local_stack;
60936244 llabel = local_label_stack;
6094− ++local_scope;
6245+ incr_local_scope();
60956246
60966247 /* handle local labels declarations */
60976248 while (tok == TOK_LABEL) {
@@ -6120,10 +6271,36 @@ static void block(int *bsym, int *csym, int is_expr) · 22 unmodified lines
61206271 block(bsym, csym, is_expr);
61216272 }
61226273 }
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+
61236300 /* pop locally defined labels */
61246301 label_pop(&local_label_stack, llabel, is_expr);
61256302 /* pop locally defined symbols */
6126− --local_scope;
6303+ decr_local_scope();
61276304 /* In the is_expr case (a statement expression is finished here),
61286305 vtop might refer to symbols on the local_stack. Either via the
61296306 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
61466323 if (tok != ';') {
61476324 gexpr();
61486325 gen_assign_cast(&func_vt);
6326+ try_call_all_cleanup();
61496327 if ((func_vt.t & VT_BTYPE) == VT_VOID)
61506328 vtop--;
61516329 else
61526330 gfunc_return(&func_vt);
6153− }
6331+ } else {
6332+ try_call_all_cleanup();
6333+ }
61546334 skip(';');
61556335 /* jump unless last stmt in top-level block */
61566336 if (tok != '}' || local_scope != 1)
@@ -6179,7 +6359,7 @@ static void block(int *bsym, int *csym, int is_expr) · 22 unmodified lines
61796359 next();
61806360 skip('(');
61816361 s = local_stack;
6182− ++local_scope;
6362+ incr_local_scope();
61836363 if (tok != ';') {
61846364 /* c99 for-loop init decl? */
61856365 if (!decl0(VT_LOCAL, 1, NULL)) {
@@ -6215,7 +6395,7 @@ static void block(int *bsym, int *csym, int is_expr) · 29 unmodified lines
62156395 gjmp_addr(c);
62166396 gsym(a);
62176397 gsym_addr(b, c);
6218− --local_scope;
6398+ decr_local_scope();
62196399 sym_pop(&local_stack, s, 0);
62206400
62216401 } else
@@ -6319,21 +6499,42 @@ static void block(int *bsym, int *csym, int is_expr) · 97 unmodified lines
63196499 expect("pointer");
63206500 ggoto();
63216501 } else if (tok >= TOK_UIDENT) {
6322− s = label_find(tok);
6323− /* put forward definition if needed */
6324− if (!s) {
6325− s = label_push(&global_label_stack, tok, LABEL_FORWARD);
6502+ s = label_find(tok);
6503+ if (!s || s->jnext == -1) {
6504+ /* put forward definition if needed */
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+ }
63266521 } else {
6522+ if (cleanup_info && is_scope_a_parent_of(scope_tracker,
6523+ s->scope))
6524+ try_call_cleanup_goto(s->scope);
6525+
63276526 if (s->r == LABEL_DECLARED)
63286527 s->r = LABEL_FORWARD;
63296528 }
6330− vla_sp_restore_root();
6529+
6530+ vla_sp_restore_root();
63316531 if (s->r & LABEL_FORWARD)
6332− s->jnext = gjmp(s->jnext);
6333− else
6334− gjmp_addr(s->jnext);
6335− next();
6336− } else {
6532+ s->jnext = gjmp(s->jnext);
6533+ else
6534+ gjmp_addr(s->jnext);
6535+ out_goto:
6536+ next();
6537+ } else {
63376538 expect("label identifier");
63386539 }
63396540 skip(';');
@@ -6346,10 +6547,21 @@ static void block(int *bsym, int *csym, int is_expr) · 6 unmodified lines
63466547 next();
63476548 s = label_find(b);
63486549 if (s) {
6550+ int is_gen = 0;
6551+
63496552 if (s->r == LABEL_DEFINED)
63506553 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+ }
63526562 s->r = LABEL_DEFINED;
6563+ if (!is_gen)
6564+ gsym(s->jnext);
63536565 } else {
63546566 s = label_push(&global_label_stack, b, LABEL_DEFINED);
63556567 }
@@ -7085,6 +7297,28 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 729 unmodified lines
70857297 }
70867298 #endif
70877299 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+
70887322 sym->a = ad->a;
70897323 } else {
70907324 /* push local reference */
@@ -7226,7 +7460,7 @@ static void gen_function(Sym *sym) · 135 unmodified lines
72267460 sym_push2(&local_stack, SYM_FIELD, 0, 0);
72277461 local_scope = 1; /* for function parameters */
72287462 gfunc_prolog(&sym->type);
7229− local_scope = 0;
7463+ reset_local_scope();
72307464 rsym = 0;
72317465 clear_temp_local_var_list();
72327466 block(NULL, NULL, 0);
@@ -7245,7 +7479,7 @@ static void gen_function(Sym *sym) · 12 unmodified lines
72457479 cur_text_section->data_offset = ind;
72467480 label_pop(&global_label_stack, NULL, 0);
72477481 /* reset local stack */
7248− local_scope = 0;
7482+ reset_local_scope();
72497483 sym_pop(&local_stack, NULL, 0);
72507484 /* end of function */
72517485 /* 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
13671367 Sym *s, **ps;
13681368 s = sym_push2(ptop, v, 0, 0);
13691369 s->r = flags;
1370+ s->scope = scope_tracker;
13701371 ps = &table_ident[v - TOK_IDENT]->sym_label;
13711372 if (ptop == &global_label_stack) {
13721373 /* modify the top most local identifier, so that
tcctok.h+2−0
@@ -123,6 +123,8 @@ · 122 unmodified lines
123123 DEF(TOK_FASTCALL3, "__fastcall__")
124124 DEF(TOK_REGPARM1, "regparm")
125125 DEF(TOK_REGPARM2, "__regparm__")
126+ DEF(TOK_CLEANUP1, "cleanup")
127+ DEF(TOK_CLEANUP2, "__cleanup__")
126128
127129 DEF(TOK_MODE, "__mode__")
128130 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