No return functions and program exit


(Michael Gottesman) #1

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

Michael


(Jordan Rose) #2

I’ve said this Michael in person, but I’ll put it on the thread for others to see:

I don’t think modeling this is worth the increase in complexity. There’s a partial workaround for anyone who notices this being a problem, which is to put any expensive work in a ‘do’ block. And actually emitting cleanups before a call to, e.g., dispatch_main would be a change in semantics, which could both break existing programs and makes the language a bit harder to reason about. The current rule that “defers happen at the close brace, releases may happen sooner” is simple. (We certainly would not want to make ‘defer’s happen before calling dispatch_main, though perhaps we should warn that they will never be executed.)

Furthermore, we have no good way to distinguish these two kinds of functions (dispatch_main vs. abort), even less so when many of them come in from C. We’d have to invent some new kind of attribute just for this case. (Admittedly, since functions like dispatch_main are rare, the attribute doesn’t have to be pretty.)

I think this is just a theoretical concern, though admittedly one Michael is running into doing his work on explicit ownership in SIL, and I don’t think we need to consider changing any behavior here.

Jordan

···

On Feb 6, 2017, at 09:48, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

Michael
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


(Joe Groff) #3

The interesting distinction here to me strikes me as being the temporal rather than exceptional nature of the exit. _exit(2) isn't an "exceptional" noreturn per se, but you'd still want to leak cleanups before it since the program's termination comes immediately after the call. If it's a profitable distinction to be made, I think there are few enough immediate-exit primitives like exit, abort, fatalError, etc. that we could probably whitelist them with a @_semantics attribute for now, and maybe use an early SIL pass to propagate the attribute in obvious cases where a function is a simple wrapper around one of those functions.

-Joe

···

On Feb 6, 2017, at 9:48 AM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.


(Greg Parker) #4

How important is it to actually clean up in the non-exceptional cases? Historically whatever work is performed before dispatch_main() or NSApplicationMain() just leaks a little and nobody cares.

(I suppose pthread_exit() is a non-exceptional exit that ought to do its best to clean up first.)

Avoiding cleanups before exceptional exits is important. We don't want to increase the code size of assert() and abort(). We also don't want to introduce additional potential crash points if the program's state is broken and it is merely trying to print a helpful error message on its way out.

···

On Feb 6, 2017, at 9:48 AM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

--
Greg Parker gparker@apple.com Runtime Wrangler


(Joe Groff) #5

And we should keep that rule. The optimizer can't move `defer`s no matter what, since they're semantically fixed to happen at end of scope, so they would always "leak" in a case like `defer { doSomething() }; abort()`. It's only value lifetimes that could be shortened, and shortening lifetimes before a noreturn call wouldn't be a change to the existing model.

-Joe

···

On Feb 6, 2017, at 10:02 AM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

I’ve said this Michael in person, but I’ll put it on the thread for others to see:

I don’t think modeling this is worth the increase in complexity. There’s a partial workaround for anyone who notices this being a problem, which is to put any expensive work in a ‘do’ block. And actually emitting cleanups before a call to, e.g., dispatch_main would be a change in semantics, which could both break existing programs and makes the language a bit harder to reason about. The current rule that “defers happen at the close brace, releases may happen sooner” is simple. (We certainly would not want to make ‘defer’s happen before calling dispatch_main, though perhaps we should warn that they will never be executed.)


(Michael Gottesman) #6

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

The interesting distinction here to me strikes me as being the temporal rather than exceptional nature of the exit. _exit(2) isn't an "exceptional" noreturn per se, but you'd still want to leak cleanups before it since the program's termination comes immediately after the call. If it's a profitable distinction to be made, I think there are few enough immediate-exit primitives like exit, abort, fatalError, etc. that we could probably whitelist them with a @_semantics attribute for now, and maybe use an early SIL pass to propagate the attribute in obvious cases where a function is a simple wrapper around one of those functions.

I am fine with either approach as long as we make a decision.

But just to bring it up in the discussion, Alexis brought up in chat an interesting point, namely what about higher level functions? I guess we don't care about that case?

Michael

···

On Feb 6, 2017, at 10:04 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 6, 2017, at 9:48 AM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

-Joe


(Michael Gottesman) #7

I’ve said this Michael in person, but I’ll put it on the thread for others to see:

I don’t think modeling this is worth the increase in complexity. There’s a partial workaround for anyone who notices this being a problem, which is to put any expensive work in a ‘do’ block. And actually emitting cleanups before a call to, e.g., dispatch_main would be a change in semantics, which could both break existing programs and makes the language a bit harder to reason about. The current rule that “defers happen at the close brace, releases may happen sooner” is simple. (We certainly would not want to make ‘defer’s happen before calling dispatch_main, though perhaps we should warn that they will never be executed.)

And we should keep that rule. The optimizer can't move `defer`s no matter what, since they're semantically fixed to happen at end of scope, so they would always "leak" in a case like `defer { doSomething() }; abort()`. It's only value lifetimes that could be shortened, and shortening lifetimes before a noreturn call wouldn't be a change to the existing model.

As long as we are clear with users that we are making this assumption that no-returns and (semantically at the SIL level) unreachables are leaking, I am happy. I can deal with that no problem. We should probably document that though.

···

On Feb 6, 2017, at 10:05 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 6, 2017, at 10:02 AM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

-Joe


(Joe Groff) #8

For higher-order functions, I think we should optimize for the common case that their generic parameters are inhabited. Like Jordan said, micromanaging the policy here is already tottering on the edge of diminishing returns for first-order noreturns; trying to accommodate every possibility of injecting an uninhabited type somewhere definitely feels like overkill.

-Joe

···

On Feb 6, 2017, at 11:04 AM, Michael Gottesman <mgottesman@apple.com> wrote:

On Feb 6, 2017, at 10:04 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 6, 2017, at 9:48 AM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

The interesting distinction here to me strikes me as being the temporal rather than exceptional nature of the exit. _exit(2) isn't an "exceptional" noreturn per se, but you'd still want to leak cleanups before it since the program's termination comes immediately after the call. If it's a profitable distinction to be made, I think there are few enough immediate-exit primitives like exit, abort, fatalError, etc. that we could probably whitelist them with a @_semantics attribute for now, and maybe use an early SIL pass to propagate the attribute in obvious cases where a function is a simple wrapper around one of those functions.

I am fine with either approach as long as we make a decision.

But just to bring it up in the discussion, Alexis brought up in chat an interesting point, namely what about higher level functions? I guess we don't care about that case?


(Michael Gottesman) #9

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

How does that sound?

Michael

···

On Feb 6, 2017, at 11:08 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 6, 2017, at 11:04 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

On Feb 6, 2017, at 10:04 AM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Feb 6, 2017, at 9:48 AM, Michael Gottesman via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

One thing that is an issue that has come up with ownership is that at the SIL level we do not distinguish in between exceptional noreturn functions and exceptional return functions.

This is important since in the non-exceptional case, we would like to clean up all of the values used in the current function before calling the no-return function. An example of such a function is dispatch_main from libdispatch. In the exceptional case though, we are ok with leaking since the program will be exiting. Beyond reducing code size (I guess?), the argument I have heard for this is that this will allow for people to examine values in the debugger since we will not have cleaned things up before the abort is called.

From what I can tell, if we are going to distinguish in between these cases, then we need a distinction in between the two baked into the compiler. Thoughts? I have code written that will enable either case to be handled as long as I can distinguish in between them at the SIL level.

The interesting distinction here to me strikes me as being the temporal rather than exceptional nature of the exit. _exit(2) isn't an "exceptional" noreturn per se, but you'd still want to leak cleanups before it since the program's termination comes immediately after the call. If it's a profitable distinction to be made, I think there are few enough immediate-exit primitives like exit, abort, fatalError, etc. that we could probably whitelist them with a @_semantics attribute for now, and maybe use an early SIL pass to propagate the attribute in obvious cases where a function is a simple wrapper around one of those functions.

I am fine with either approach as long as we make a decision.

But just to bring it up in the discussion, Alexis brought up in chat an interesting point, namely what about higher level functions? I guess we don't care about that case?

For higher-order functions, I think we should optimize for the common case that their generic parameters are inhabited. Like Jordan said, micromanaging the policy here is already tottering on the edge of diminishing returns for first-order noreturns; trying to accommodate every possibility of injecting an uninhabited type somewhere definitely feels like overkill.

-Joe


(Joe Groff) #10

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

-Joe

···

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).


(Michael Gottesman) #11

SGTM!

Michael

···

On Feb 6, 2017, at 11:25 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

-Joe


(Jordan Rose) #12

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

Jordan

···

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com> wrote:


(John McCall) #13

I think I agree with this. :slight_smile:

One reasonable approach to fixing the user problem Michael is identifying without providing special-case behavior to noreturn calls would be to simply make a stronger language guarantee about value liveness in general. For example, we could say that if a value is "obviously" not used in or after a particular statement, then it is guaranteed to have been destroyed before that statement executes. We can use the same definition of "obvious" that DI uses, which gives us a clear implementation path: we just run a lifetime-shortening pass as a mandatory optimization, possibly even as part of DI.

Of course, that's not necessarily great for debugging.

John.

···

On Feb 6, 2017, at 2:25 PM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.


(Michael Gottesman) #14

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

On the other hand, this is safe to do in the short term. We can special case asserts. One thing to consider though is if this should be provided to users. If not, we can just use semantics. Otherwise, we would need to discuss how to surface this at the language level.

Michael

···

On Feb 6, 2017, at 11:44 AM, Jordan Rose <jordan_rose@apple.com> wrote:

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

Jordan


(Erik Eckstein) #15

I’m not sure if I understood.
What if there is a call to a function and that conditionally calls a noreturn function:

func foo() {
  let x = Myclass()
  bar(true)
  // release x here?
}

func bar(_ dontReturn: Bool) {
  if (dontReturn) {
    noreturn_func()
  }
}

Is it even possible to “clean up before” in such a case?

Erik

···

On Feb 6, 2017, at 12:19 PM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

On Feb 6, 2017, at 11:44 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

On the other hand, this is safe to do in the short term. We can special case asserts. One thing to consider though is if this should be provided to users. If not, we can just use semantics. Otherwise, we would need to discuss how to surface this at the language level.

Michael

Jordan

_______________________________________________
swift-dev mailing list
swift-dev@swift.org <mailto:swift-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-dev


(Andrew Trick) #16

Sorry I didn't jump in yesterday. I'm afraid I don't follow most of the reasoning expressed in the thread. I do completely understand Jordan's points.

'noreturn' functions are called from may-return functions. Guaranteeing cleanup would result in inconsistent behavior as a result of optimization.

The optimizer can always shorten lifetimes when it determines that the caller can't access the object. But I don't see what that has to do with 'noreturn'.

I agree that we *could* add a special "cleanup before" semantic tag for some C functions, but I'm not aware of a need to do that and there are definite drawbacks.

-Andy

···

On Feb 6, 2017, at 12:19 PM, Michael Gottesman via swift-dev <swift-dev@swift.org> wrote:

On Feb 6, 2017, at 11:44 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

On the other hand, this is safe to do in the short term. We can special case asserts. One thing to consider though is if this should be provided to users. If not, we can just use semantics. Otherwise, we would need to discuss how to surface this at the language level.

Michael


(Michael Gottesman) #17

I’m not sure if I understood.
What if there is a call to a function and that conditionally calls a noreturn function:

func foo() {
  let x = Myclass()
  bar(true)
  // release x here?
}

func bar(_ dontReturn: Bool) {
  if (dontReturn) {
    noreturn_func()
  }
}

Is it even possible to “clean up before” in such a case?

The no return function in a certain sense causes the scope for x to never end. So no cleanup is needed. The cleanup for x should be after bar always.

···

On Feb 6, 2017, at 3:41 PM, Erik Eckstein <eeckstein@apple.com> wrote:

Erik

On Feb 6, 2017, at 12:19 PM, Michael Gottesman via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:44 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

On the other hand, this is safe to do in the short term. We can special case asserts. One thing to consider though is if this should be provided to users. If not, we can just use semantics. Otherwise, we would need to discuss how to surface this at the language level.

Michael

Jordan

_______________________________________________
swift-dev mailing list
swift-dev@swift.org <mailto:swift-dev@swift.org>
https://lists.swift.org/mailman/listinfo/swift-dev


(Michael Gottesman) #18

Here is my suggestion:

1. We assume by default the leaking case.
2. We change noreturn functions from C to maybe have a special semantic tag on them that says that cleanups should occur before them (i.e. UIApplicationMain).

I'm not sure what you mean by this. Functions from C exist in both groups, and I don't see why one assumption is better than the other.

I feel that "clean up before" is the safer ground case, and if we do any work to whitelist a group, it should be for the common "leakable" noreturns, like exit/_exit/abort/fatalError. That way, we momentarily burn some pointless cycles in the case we get it "wrong" rather than permanently leak memory.

I don't like this because of the reverse issue: under -Onone, you may want to pop back up the stack in the debugger and see what values you had, and they won't be available. It's almost always possible to get things released sooner; usually more awkward to get them to stay alive.

On the other hand, this is safe to do in the short term. We can special case asserts. One thing to consider though is if this should be provided to users. If not, we can just use semantics. Otherwise, we would need to discuss how to surface this at the language level.

Michael

Sorry I didn't jump in yesterday. I'm afraid I don't follow most of the reasoning expressed in the thread. I do completely understand Jordan's points.

'noreturn' functions are called from may-return functions. Guaranteeing cleanup would result in inconsistent behavior as a result of optimization.

The optimizer can always shorten lifetimes when it determines that the caller can't access the object. But I don't see what that has to do with 'noreturn'.

I agree that we *could* add a special "cleanup before" semantic tag for some C functions, but I'm not aware of a need to do that and there are definite drawbacks.

No worries. (TBH I was just trying to get a decision and was posting straw men proposals). Basically after further talk off list, we got in agreement to go with the scope splitting approach (i.e. no cleanups).

What I really just wanted was something definitive that I could explicitly document. I added a small blurb to ./docs/ARCOptimization.*. I need to add an example and make it slightly clearer.

Michael

···

On Feb 7, 2017, at 11:56 AM, Andrew Trick <atrick@apple.com> wrote:

On Feb 6, 2017, at 12:19 PM, Michael Gottesman via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:44 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

On Feb 6, 2017, at 11:25, Joe Groff via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

On Feb 6, 2017, at 11:22 AM, Michael Gottesman <mgottesman@apple.com <mailto:mgottesman@apple.com>> wrote:

-Andy