This should not go in, it's WIP, just trolling for comments...
License: Bugroff
Changelog:
- include/wine/excpetion.h - memory/global.c
Implement gcc-specific "__TYPED_TRY" macro supposedly capable of intercepting return and running the finally clause. If it compiles, it should work on x86... If it fails to compile, it needs you to specify the return type as in
__TYPED_TRY(float) { } __FINALLY(func) { } __ENDTRY
. Other arches may have much less success ;) of course, almost any problem of this kind should be fixed by turning __TRY into the appropriate __TYPED_TRY. __TRY generates warnings, some may be fixable.
Untested, and probably broken... but this should give you an idea of where I'm headed. From here, I can probably implement __try and friends much as before, with the twist that __try is just __typed_try(int ****) or what-have-you.
-gmt
-- diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.vanilla/include/wine/exception.h ./include/wine/exception.h --- ../wine.vanilla/include/wine/exception.h 2003-01-29 21:50:14.000000000 -0600 +++ ./include/wine/exception.h 2003-05-14 21:37:51.000000000 -0500 @@ -74,6 +74,94 @@
#else /* USE_COMPILER_EXCEPTIONS */
+#if defined(__GNUC__) + +#define __TYPED_TRY(return_type) \ + if ( ({ \ + __label__ __typed_try_block_setup, __typed_try_block_entry, \ + __typed_try_block_exit_no_return, __typed_try_block_exit_return0, \ + __typed_try_block_exit_return1, __typed_try_block_exit_full; \ + __WINE_FRAME __wf; \ + typeof(return_type) __scope_return_val; \ + auto typeof(return_type) __scope_tryblock_fn(); \ + goto __typed_try_block_setup; \ + \ + __typed_try_block_entry: \ + __scope_return_val = __scope_tryblock_fn(); \ + __wine_pop_frame( &__wf.frame ); \ + goto __typed_try_block_exit_return0; \ + \ + __typed_try_block_exit_return1: \ + return __scope_return_val; \ + \ + typeof(return_type) __scope_tryblock_fn() \ + { \ + { + +#define __TRY __TYPED_TRY(unsigned int ****) + +#define __FINALLY(func) \ + } \ + /* this unwinds the __scope_tryblock_fn call */ \ + goto __typed_try_block_exit_no_return; \ + } \ + \ + __typed_try_block_setup: \ + __wf.frame.Handler = (PEXCEPTION_HANDLER)__wine_finally_handler; \ + __wf.u.finally_func = (func); \ + __wine_push_frame( &__wf.frame ); \ + goto __typed_try_block_entry; \ + \ + __typed_try_block_exit_return0: \ + (func)(1); \ + goto __typed_try_block_exit_return1; \ + \ + __typed_try_block_exit_no_return: \ + __wine_pop_frame( &__wf.frame ); \ + (func)(1); \ + { \ + { + +#define __EXCEPT(func) \ + } \ + /* this unwinds the __scope_tryblock_fn call */ \ + goto __typed_try_block_exit_no_return; \ + } \ + \ + __typed_try_block_exit_return0: \ + goto __typed_try_block_exit_return1; \ + \ + __typed_try_block_exit_no_return: \ + __wine_pop_frame( &__wf.frame ); \ + goto __typed_try_block_exit_full; \ + \ + __typed_try_block_setup: \ + __wf.frame.Handler = (PEXCEPTION_HANDLER)__wine_exception_handler; \ + __wf.u.filter = (func); \ + __wine_push_frame( &__wf.frame ); \ + if (!(setjmp( __wf.jmp ))) { \ + goto __typed_try_block_entry; \ + } else { \ + const __WINE_FRAME * const __eptr WINE_UNUSED = &__wf; \ + { + +#define __ENDTRY \ + } \ + } \ + __typed_try_block_exit_full: 0; \ + }) ) { } else { } + +#define __BREAK goto __typed_try_block_exit_no_return + +#else /* __GNUC__ */ + +/* these are the old wine __TRY macros. They are not + * capable of intercepting returns, which means the + * return-from-tryblock feature of the above macros + * shouldn't be used in parts of wine which will be used + * with non-gcc compilers. + */ + #define __TRY \ do { __WINE_FRAME __f; \ int __first = 1; \ @@ -81,6 +169,8 @@ { \ do {
+#define __TYPED_TRY(x) __TRY + #define __EXCEPT(func) \ } while(0); \ __wine_pop_frame( &__f.frame ); \ @@ -114,6 +204,9 @@ } \ } while (0);
+#define __BREAK break + +#endif /* __GNUC__*/
typedef DWORD (CALLBACK *__WINE_FILTER)(PEXCEPTION_POINTERS); typedef void (CALLBACK *__WINE_FINALLY)(BOOL); diff -ur --minimal --exclude-from=/home/greg/bin/winetreediff_excl ../wine.vanilla/memory/global.c ./memory/global.c --- ../wine.vanilla/memory/global.c 2003-05-14 15:06:26.000000000 -0500 +++ ./memory/global.c 2003-05-14 21:38:13.000000000 -0500 @@ -1251,7 +1251,7 @@ if (ISPOINTER(pmem)) { if (HeapValidate( GetProcessHeap(), 0, pmem )) { handle = (HGLOBAL)pmem; /* valid fixed block */ - break; + __BREAK; } handle = POINTER_TO_HANDLE(pmem); } else @@ -1263,7 +1263,7 @@ test = maybe_intern->Pointer; if (HeapValidate( GetProcessHeap(), 0, (char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */ HeapValidate( GetProcessHeap(), 0, maybe_intern )) /* intern valid arena? */ - break; /* valid moveable block */ + __BREAK; /* valid moveable block */ } handle = 0; SetLastError( ERROR_INVALID_HANDLE );
"Gregory M. Turner" gmturner007@ameritech.net writes:
- include/wine/excpetion.h
- memory/global.c
Implement gcc-specific "__TYPED_TRY" macro supposedly capable of intercepting return and running the finally clause. If it compiles, it should work on x86...
Cool! now you can start considering how to support continue, break, and goto ;-)
(I don't want to discourage you, but I think you will eventually come to realize that the only way to make this work right is to do it in the compiler)
On Wednesday 14 May 2003 11:08 pm, Alexandre Julliard wrote:
"Gregory M. Turner" gmturner007@ameritech.net writes:
- include/wine/excpetion.h
- memory/global.c
Implement gcc-specific "__TYPED_TRY" macro supposedly capable of intercepting return and running the finally clause. If it compiles, it should work on x86...
Cool! now you can start considering how to support continue, break, and goto ;-)
(I don't want to discourage you, but I think you will eventually come to realize that the only way to make this work right is to do it in the compiler)
Don't worry, we are in agreement on this. I have spent a fair amount of time trying to decide whether this problem is fixable without such a measure, and I suspect the answer is no, or, at least, not without doing an inordinate amount of work and writing lots of asm.
But, for the forseeable future, a majority of wine users & developers will not have such a thing. So, in my view, it makes sense to improve the existing __TRY family of macros nevertheless, and to create a partial implementation of the __try syntax as well.
FWIW, I think break/continue can actually be implemented in this framework -- that was already on my TODO list -- I think I just have to put a "dummy" loop inside the try-block function, and have more labels for the various exit conditions. Goto out of the try block is another story, and of course there are other limitations... but this would, at least, provide some coverage for the stuff that wine already relies on, despite the missing implementation. The alternative is to work around the bugs it will create in our RPC implementation not to have such support, which is going to get dicey.
When/if gcc does it, great, we just use the implementation of __TRY in terms of __try, we don't have to change a thing. If, for example, after some research, the -fasync-unwind-tables thing pans out, that's fine too; we can add that in, but not all platforms support this, even for gcc, so we still need a pure-C portable alternative to be supported by wine to some reasonable extent.
The only way I could see them working /portably/ is to use our own preprocessor instead of, or in addition to, the C preprocessor, but that could slow down our already slightly onerous build process.
On Thursday 15 May 2003 08:46 pm, Gregory M. Turner wrote:
FWIW, I think break/continue can actually be implemented in this framework -- that was already on my TODO list -- I think I just have to put a "dummy" loop inside the try-block function, and have more labels for the various exit conditions.
nope. 'cause it's illegal to have a break/continue hanging around without something to break/continue out of. But we could have to have "__TYPED_TRY" "__ACHEY_BREAKEY_TYPED_TRY" macros :(
On May 16, 2003 12:00 am, Gregory M. Turner wrote:
nope. 'cause it's illegal to have a break/continue hanging around without something to break/continue out of. But we could have to have "__TYPED_TRY" "__ACHEY_BREAKEY_TYPED_TRY" macros :(
Greg,
I think we're barking up the wrong tree. Vast majority of Windows apps nowadays are C++. Of the few that are C-only, most will compile with a C++ compiler. In other words, if we find a C++ solution for the SEH problem, we would have covered probably more than 95% of apps. Not perfect, but good enough.
If I understand you guys correctly, the problem should be solvable in C++. Let's go for the low hanging fruit first, it makes good sense.
On Friday 16 May 2003 12:05 am, Dimitrie O. Paun wrote:
On May 16, 2003 12:00 am, Gregory M. Turner wrote:
nope. 'cause it's illegal to have a break/continue hanging around without something to break/continue out of. But we could have to have "__TYPED_TRY" "__ACHEY_BREAKEY_TYPED_TRY" macros :(
Greg,
I think we're barking up the wrong tree. Vast majority of Windows apps nowadays are C++. Of the few that are C-only, most will compile with a C++ compiler. In other words, if we find a C++ solution for the SEH problem, we would have covered probably more than 95% of apps. Not perfect, but good enough.
If I understand you guys correctly, the problem should be solvable in C++. Let's go for the low hanging fruit first, it makes good sense.
unfortunately, this doesn't help with MIDL-generated code, which is my primary motivation here...
My concern, aside from that it won't work without all these gcc-isms, is that by creating a similar syntax to __try and friends, which only implement some of the real semantics of these constructs, we create a "false" sense of security. Code utilizing these might compile, and then yield some horrible and confusing result (of course, that's kind of what we have now, anyhow, with dummy Rpc EH macros)...
goto is a good problem to mention, because unlike break/continue, if they did a goto out of a try-block, it would compile, but fail to pop the exception record or run finally... not sure if there is some way to prevent that.
On May 16, 2003 02:21 am, Gregory M. Turner wrote:
unfortunately, this doesn't help with MIDL-generated code, which is my primary motivation here...
I know, but I was hoping to use your hard earned knowladge to solve this big hole that we have in Winelib... :) Any chance you can look at it from the C++ angle? BTW, can't we compile the MIDL-generated code with a C++ compiler?
On Friday 16 May 2003 08:15 am, Dimitrie O. Paun wrote:
On May 16, 2003 02:21 am, Gregory M. Turner wrote:
unfortunately, this doesn't help with MIDL-generated code, which is my primary motivation here...
I know, but I was hoping to use your hard earned knowladge to solve this big hole that we have in Winelib... :) Any chance you can look at it from the C++ angle? BTW, can't we compile the MIDL-generated code with a C++ compiler?
This is a possibility. Another, which I never thought of until now, would be to define macros to support RpcTryExcept syntax, which have the useful advantage of a trailing __ENDTRY-type syntax.
Also, I have learned that gcc 3.3 has a new preprocessing feature: directives may be embedded in macros; I think this means we could do stuff like #define return something_else, within our macros. This could maybe fix break, return, even goto... obviously it would be a while before it was widely available. Just brainstorming here...
Dimi, here's an evident C++ angle, how does this strike you? We use g++ to generate the exceptions, and then unwind them through our C code, using -fexceptions. Probably easy, if inefficient, compared to the mess I've been proposing:
In wine's first C++ file, we implement the following C api:
extern seh_te_outcome try_except_beastie( tryblk_fn_ptr, filter_fn_ptr, except_fn_ptr ) extern seh_tf_outcome try_finally_beastie( tryblk_fn_ptr,finally_fn_ptr ).
The former uses catch(...) to handle exceptions; the latter uses a destructor to achieve unwind goodness. Each calls through the function pointers it is provided by C macros, which still use gcc-specific nested functions as before.
We still have the lexical constraints of C to deal with, in C code, so we still lose break and continue, I guess, at least until gcc 3.3. But these generate nice compile failures that will get fixed at design-time. Meanwhile, goto out of a tryblock should work, if I understand how gcc would implement this.
Pros: Actually sort of works, and actually somewhat portable.
Presumably allows C++ winelib apps to work better; makes wine play nicer with C++ eh and other -fexceptions libs.
Might be a good "excuse" to start allowing portions of wine which are C++-specific.
Cons:
Wine binaries are much bloated, and maybe less optimised. -fexceptions is known to cause huge size increases, I'm afraid.
If we call through libs compiled without -fexceptions, bad things will happen.
Depending on how much we want to rely on this, we now need g++ for a working wine. Perhaps, this is inevitable and we shouldn't worry about it. Presumably, there are some known caveats to mixing C++ and wine?
Might be a good "excuse" to start allowing portions of wine which are C++-specific.
Not sure this is workable with "return"... ?
Any of the above ideas strike anyone's fancy?
I guess the first question to ask, before all of the above is: which is a worse sacrifice for wine? Requiring compiler support for this, or an extra parsing phase? Or just having a broken dummy implementation like we do now? OK, sorry to harp on this subject, I will shut up now, as I am sure you are all sick of this ;)
"Gregory M. Turner" gmturner007@ameritech.net writes:
I guess the first question to ask, before all of the above is: which is a worse sacrifice for wine? Requiring compiler support for this, or an extra parsing phase? Or just having a broken dummy implementation like we do now?
For Winelib apps, the solution is to add support to the compiler. For IDL-generated code, the solution is to make our IDL compiler generate code that uses the existing __TRY macros (or even generates the C code directly without using the macros if this allows more optimizations).
There is some discussion on mingw-developer about merging Capsers SEH patches but there are patent issues as borland owns the patent on C++ Style EH in C. The patent is BS as it even sights prior art but still I dont know who wants to take the risk on going to court for this. Now that M$ owns a large chunck of borland this might happen.
Here is the email in question
<snip>
Well, I don't think I have the time for this. It was quite a battle to get the fastcall patch into gcc, and this was only a (IIRC) ~10 or ~20 KB patch. Compare that to the SEH patch which is ~370 KB (and not even complete yet) and which may even violate Borland's patent. The patch is also written by me when I was a gcc newbie and I have probably made some mistakes. It would be nice if an experienced gcc hacker would review and improve the patch.
I will however help in any way I can integrating the patch into gcc 3.4 if needed.
Finally, a gcc with only __try/__finally is only marginally better than a gcc without any SEH at all.
Casper Hornstrup
Alexandre Julliard wrote:
"Gregory M. Turner" gmturner007@ameritech.net writes:
I guess the first question to ask, before all of the above is: which is a worse sacrifice for wine? Requiring compiler support for this, or an extra parsing phase? Or just having a broken dummy implementation like we do now?
For Winelib apps, the solution is to add support to the compiler. For IDL-generated code, the solution is to make our IDL compiler generate code that uses the existing __TRY macros (or even generates the C code directly without using the macros if this allows more optimizations).
On Sunday 18 May 2003 12:04 pm, Steven Edwards wrote:
There is some discussion on mingw-developer about merging Capsers SEH patches but there are patent issues as borland owns the patent on C++ Style EH in C. The patent is BS as it even sights prior art but still I dont know who wants to take the risk on going to court for this. Now that M$ owns a large chunck of borland this might happen.
Regarding this, I think we all know where Borland can stick this patent to get the best ROI ;)
I mean, it would be suicidal for them to take some poor schmuck like me to court over this... their shareholders (including me) would probably fire the board before they'd tolerate the fallout from such an act. And what damages are they going to recover? The best they could hope for would be a crapload of bad press and some kind of cease-and-decist order... they sure ain't gonna get much out of me, I'm broke ;) Anyhow, this is a discussion for another forum, to which I do not subscribe.
Well, I don't think I have the time for this. It was quite a battle to get the fastcall patch into gcc, and this was only a (IIRC) ~10 or ~20 KB patch. Compare that to the SEH patch which is ~370 KB (and not even complete yet) and which may even violate Borland's patent. The patch is also written by me when I was a gcc newbie and I have probably made some mistakes. It would be nice if an experienced gcc hacker would review and improve the patch.
I will however help in any way I can integrating the patch into gcc 3.4 if needed.
Finally, a gcc with only __try/__finally is only marginally better than a gcc without any SEH at all.
Well, it is the lower-hanging fruit. With __except, you are looking at interactions with C++ exceptions, which could get interesting, and hard. Asking for __finally is just to say "hey, can't we run some code if the bloody stack is going to unwind so we don't have memory leaks?" So it'd be better than nothing, perhaps there is even a good way to create __except macros once you have language support for __finally, I've never thought about that.
What concerns me more is that judging from what I see floating around out there, the gcc devs just plain aren't interested. Some of them are saying "let's be flexible" but the majority seem to be saying "Do it in C++, C should not absorb any new fancy features unless they are standardized by ANSI" or some other discouraging thing.
Alexandre Julliard wrote:
For Winelib apps, the solution is to add support to the compiler. For IDL-generated code, the solution is to make our IDL compiler generate code that uses the existing __TRY macros (or even generates the C code directly without using the macros if this allows more optimizations).
I'm not sure I'm sold on this... I mean, I realize maybe I should be the one selling you if I want to get a patch in, but could you elaborate on the "why" of this a little bit? I like the idea of generating __TRY from widl instead of RpcTryExcept, that's a consistiency issue basically... but expecting compiler support to materialize for seh seems a bit optimistic, frankly.
Why /not/ a pre-pre-processor? It would allow us to implement this properly and portably... I'm sure the performance impact at compile time could be managed, perhaps by only running it against the code that needs it... such files could be marked or discovered at build-time in any number of ways.
Also, I was hoping to hear how everbody feels about -fexceptions? It would seem that without it, g++ exceptions are going to break in winelib... or can those somehow route themselves through the CxxExcept stuff (I presume no, since those rely on compiler-generated unwind-tables that AFAIK gcc doesn't support).
What concerns me more is that judging from what I see floating around out there, the gcc devs just plain aren't interested. Some of them are saying "let's be flexible" but the majority seem to be saying "Do it in C++, C should not absorb any new fancy features unless they are standardized by ANSI" or some other discouraging thing.
Maybe the main gcc developers but the mingw team seems to support the idea. Once it gets in Mingw it is only another minor release before it makes it in to GCC HEAD. The ReactOS team introduced the fastcall patches and that took a while but I think they are in the main branch now.
I'm not sure I'm sold on this... I mean, I realize maybe I should be the one selling you if I want to get a patch in, but could you elaborate on the "why" of this a little bit? I like the idea of generating __TRY from widl instead of RpcTryExcept, that's a consistiency issue basically... but expecting compiler support to materialize for seh seems a bit optimistic, frankly.
Well compiler support is going to needed for us on the ReactOS side one day not to far off and we are going to have to implement it. With or without the WINE teams help we are going to do this one day. It would be a better if we could all work together to get this done rather then implement a bunch of half-broken hacks.
Thanks Steven
__________________________________ Do you Yahoo!? The New Yahoo! Search - Faster. Easier. Bingo. http://search.yahoo.com
Steven Edwards wrote:
Maybe the main gcc developers but the mingw team seems to support the idea. Once it gets in Mingw it is only another minor release before it makes it in to GCC HEAD.
This is not quite how GCC development works ... From what I've seen on the gcc lists, I wouldn't expect __try/__finally to make it unless the core maintainers can be convinced that it is useful, well-defined and won't hurt future maintainability (they've been bitten in the past with other GCC extensions ...).
What's mostly missing as far as I can see it is an actual definition of the intended semantics of the construct, in the style of the C standard; defining in particular the interactions of the new feature with all other existing standard features and GNU extensions.
Also, the current discussion was mostly about using __try/__finally in order to implement pthread cancellation cleanups. If there is a need for this feature outside of that area (e.g. for Winelib), it probably can't hurt to voice that request on the GCC lists.
Bye, Ulrich
"Gregory M. Turner" gmturner007@ameritech.net writes:
I'm not sure I'm sold on this... I mean, I realize maybe I should be the one selling you if I want to get a patch in, but could you elaborate on the "why" of this a little bit?
Because it's the right place for it, and because other solutions are simply not going to work.
Why /not/ a pre-pre-processor? It would allow us to implement this properly and portably... I'm sure the performance impact at compile time could be managed, perhaps by only running it against the code that needs it... such files could be marked or discovered at build-time in any number of ways.
You can't make it portable anyway, you will still need nested functions and other gcc-isms. Unless you want to reimplement a full C compiler in your preprocessor...
On Monday 19 May 2003 12:02 pm, Alexandre Julliard wrote:
You can't make it portable anyway, you will still need nested functions and other gcc-isms. Unless you want to reimplement a full C compiler in your preprocessor...
I don't know, I haven't thought this all the way through. Obviously, there is the potential for this to become rather involved depending on the approach. Might be easier to do on a post-preprocessed file... Allowing for gcc-isms makes it easier, but obviously defeats the purpose of making it portable to different compilers.
A portable approach probably would require a full lexical breakdown and significant restructuring of the affected source files, at least in the affected portions of the source. This would require a significant amount of computational expense for the consumer at compile time, and maybe at run-time too, at least for non-gcc builds.
I am sure that there is no shortage of appropriately-licensed C lexer/parsers out there I could borrow code from, so maybe the implementation part might not be so difficult as it seems at a glance. If you are open to the concept, Alexandre, I'd be happy to experiment. If not, I'd be happy to give up for the time being, and focus on other things ;)
"Gregory M. Turner" gmturner007@ameritech.net writes:
I am sure that there is no shortage of appropriately-licensed C lexer/parsers out there I could borrow code from, so maybe the implementation part might not be so difficult as it seems at a glance. If you are open to the concept, Alexandre, I'd be happy to experiment. If not, I'd be happy to give up for the time being, and focus on other things ;)
It's not so much the concept, but I think you greatly underestimate the complexity of the task. Standard C simply doesn't have the expressive power you need, so you will end up basically reinventing a C compiler; and the end result not only won't work as well as a gcc-integrated solution, but will be even more work to implement in the first place.
Of course it's your time to spend as you like, and if hacking C parsers is your idea of fun, by all means go ahead. But if you are looking for ways to help Wine, doing just about anything else would be more productive in the end IMO.
On May 17, 2003 05:17 pm, Gregory M. Turner wrote:
Depending on how much we want to rely on this, we now need g++ for a working wine. Perhaps, this is inevitable and we shouldn't worry about it. Presumably, there are some known caveats to mixing C++ and wine?
I have to agree with Alexandre on this one: there doesn't seem to be a need to add such requirements to Wine, as here we control the code, we should just use the macros we have.
I am personally more concerned about Winelib apps. There the code is written, and it's probably not easy (and for sure undesirable) to change. There I think it's reasonable to compile with -fexceptions if you do use SEH. Can we solve the problem (even partially) in that context?
Gregory M. Turner wrote:
On Wednesday 14 May 2003 11:08 pm, Alexandre Julliard wrote:
(I don't want to discourage you, but I think you will eventually come to realize that the only way to make this work right is to do it in the compiler)
Don't worry, we are in agreement on this. I have spent a fair amount of time trying to decide whether this problem is fixable without such a measure, and I suspect the answer is no, or, at least, not without doing an inordinate amount of work and writing lots of asm.
[snip]
When/if gcc does it, great, we just use the implementation of __TRY in terms of __try, we don't have to change a thing. If, for example, after some research, the -fasync-unwind-tables thing pans out, that's fine too; we can add that in, but not all platforms support this, even for gcc, so we still need a pure-C portable alternative to be supported by wine to some reasonable extent.
Has anyone investigated what work needs to be done for gcc to support these kinds of try/except things?
On Friday 16 May 2003 01:10 am, David Fraser wrote:
Has anyone investigated what work needs to be done for gcc to support these kinds of try/except things?
yes, there are patches. I think some mingw's have it too.