ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:89797] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
@ 2018-11-14 19:13 ` alanwucanada
  2018-12-05  7:03 ` [ruby-core:90300] " ko1
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: alanwucanada @ 2018-11-14 19:13 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been reported by alanwu (Alan Wu).

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: 
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90300] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
  2018-11-14 19:13 ` [ruby-core:89797] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied alanwucanada
@ 2018-12-05  7:03 ` ko1
  2018-12-05 15:50 ` [ruby-core:90317] " alanwucanada
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: ko1 @ 2018-12-05  7:03 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by ko1 (Koichi Sasada).


hi,

how about to call `return` event hook at tailcall? There is no need to introduce new API proposed at [Bug #15313].

```
def bar
end

iseq = RubyVM::InstructionSequence.new("def foo; bar; end", __FILE__, __FILE__, __LINE__, tailcall_optimization: true)
iseq.eval

TracePoint.new(:call, :return){|tp| p tp}.enable{
  foo
}

#=>
#<TracePoint:call `foo'@/home/ko1/src/ruby/gitruby/test.rb:4>
#<TracePoint:return `foo'@/home/ko1/src/ruby/gitruby/test.rb:4>
#<TracePoint:call `bar'@/home/ko1/src/ruby/gitruby/test.rb:1>
#<TracePoint:return `bar'@/home/ko1/src/ruby/gitruby/test.rb:2>

```

patch:

```
diff --git a/compile.c b/compile.c
index d97cf4e8c6..696e127b9a 100644
--- a/compile.c
+++ b/compile.c
@@ -3144,13 +3144,15 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
 
 	if (piobj) {
 	    struct rb_call_info *ci = (struct rb_call_info *)piobj->operands[0];
-	    if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) {
-		if (piobj->operands[2] == 0) { /* no blockiseq */
-		    ci->flag |= VM_CALL_TAILCALL;
+            if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) {
+                if (piobj->operands[2] == 0) { /* no blockiseq */
+                    goto change_to_tailcall;
 		}
 	    }
 	    else {
+              change_to_tailcall:
 		ci->flag |= VM_CALL_TAILCALL;
+                piobj->insn_info.events = RUBY_EVENT_RETURN;
 	    }
 	}
     }
```

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75407

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [ruby-core:90317] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
  2018-11-14 19:13 ` [ruby-core:89797] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied alanwucanada
  2018-12-05  7:03 ` [ruby-core:90300] " ko1
@ 2018-12-05 15:50 ` alanwucanada
  2018-12-05 16:33 ` [ruby-core:90318] " ko1
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: alanwucanada @ 2018-12-05 15:50 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by alanwu (Alan Wu).


The main concern I have with this approach is that there is no reasonable value we can make `Tracepoint#return_value` return when we trigger it due to tailcall:

```
def bar
  :"bar's return value"
end

iseq = RubyVM::InstructionSequence.new("def foo; bar; end", __FILE__, __FILE__, __LINE__, tailcall_optimization: true)
iseq.eval

TracePoint.new(:return) {|tp|
  p tp
  p tp.return_value
}.enable{
  foo
}
```

Outputs the following with the patch from https://bugs.ruby-lang.org/issues/15303#note-2 applied:

```
#<TracePoint:return `foo'@./test.rb:5>
main
#<TracePoint:return `bar'@./test.rb:3>
:"bar's return value"
```

Clearly, foo doesn't return `main`; there is no meaningful value we can put for `#return_value` since semantically, foo hasn't returned yet.
With this patch applied, `#return_value` is not reliable anymore for return events.
I made #15313 because I felt it's the most backward compatible approach. 

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75422

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90318] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2018-12-05 15:50 ` [ruby-core:90317] " alanwucanada
@ 2018-12-05 16:33 ` ko1
  2018-12-05 16:50 ` [ruby-core:90319] " alanwucanada
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: ko1 @ 2018-12-05 16:33 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by ko1 (Koichi Sasada).


Yes, the patch should return `nil` (I forgot to support it).

I think we can change the semantic of tailcall as a method call/return flow I proposed.
What kind of issue on this change?



----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75423

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90319] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2018-12-05 16:33 ` [ruby-core:90318] " ko1
@ 2018-12-05 16:50 ` alanwucanada
  2018-12-05 17:02 ` [ruby-core:90321] " ko1
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: alanwucanada @ 2018-12-05 16:50 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by alanwu (Alan Wu).


If we return `nil` for `#return_value`, users can't tell whether the nil is from the method actually returning nil, or a `nil` from tailcall.
I think the return event should be reserve for only real returns, because of its name.



----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75424

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90321] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2018-12-05 16:50 ` [ruby-core:90319] " alanwucanada
@ 2018-12-05 17:02 ` ko1
  2018-12-05 17:19 ` [ruby-core:90323] " alanwucanada
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: ko1 @ 2018-12-05 17:02 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by ko1 (Koichi Sasada).


or `raise` on `return_value` ?

it is irregular case. I think tailcall is not normal call (it is same as a method call by lexicial).

```
foo() # tailcall
```

we can see:

```
return_and_call(:foo)
```

and nobody think it is strange.

in other words, using tailcall, we can define it as "transformation from former syntax to latter syntax~ we can think.

I want to know the real issue by this spec.

I want to know the 

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75426

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90323] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2018-12-05 17:02 ` [ruby-core:90321] " ko1
@ 2018-12-05 17:19 ` alanwucanada
  2018-12-08  1:31 ` [ruby-core:90376] " ko1
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: alanwucanada @ 2018-12-05 17:19 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by alanwu (Alan Wu).


I personally don't see an issue with this spec, besides that it would introduce a breaking change one way or the other. I think it would fix the `next` command in byebug, though.

I've asked David Rodríguez, the creator of Byebug to join the discussion on Github. Hopefully we get to hear from him.



----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75428

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90376] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2018-12-05 17:19 ` [ruby-core:90323] " alanwucanada
@ 2018-12-08  1:31 ` ko1
  2018-12-08  6:33 ` [ruby-core:90377] " alanwucanada
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: ko1 @ 2018-12-08  1:31 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by ko1 (Koichi Sasada).


Ah, I have another strong idea (forgot to propose).

Cancel tailcall opt when `return` event is specified.


----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75485

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90377] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (7 preceding siblings ...)
  2018-12-08  1:31 ` [ruby-core:90376] " ko1
@ 2018-12-08  6:33 ` alanwucanada
  2018-12-11 22:20 ` [ruby-core:90428] " deivid.rodriguez
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 12+ messages in thread
From: alanwucanada @ 2018-12-08  6:33 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by alanwu (Alan Wu).

File no-tco-no-problem.patch added

ko1 (Koichi Sasada) wrote:
> Cancel tailcall opt when `return` event is specified.

I think anyone who goes through all the trouble to enable tailcall elimination right now relies on it to avoid stack overflow.
Why else would someone use it? It doesn't make your program faster, it's cumbersome to enable, and it erases part of your stack trace which makes debugging harder.

Making this change seems to me replacing a problem with a different one. It is a problem that affects way less people admittedly, but I feel that it would be punishing functional programmers for the benefit of everyone else.

If we just want to fix the problem most people have today, i.e., byebug's `next` command's breakage, making Forwardable not use TCO is good enough. It will still be broken for tailcall optimized code, but at least most people won't run into this problem.
That might be the most pragmatic "fix", and it's a simple one. With it, we can keep ignoring this problem and wait till someone complains.

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75487

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.


---Files--------------------------------
no-tco-no-problem.patch (520 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90428] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (8 preceding siblings ...)
  2018-12-08  6:33 ` [ruby-core:90377] " alanwucanada
@ 2018-12-11 22:20 ` deivid.rodriguez
  2018-12-12  6:06 ` [ruby-core:90437] " ko1
  2018-12-12 12:07 ` [ruby-core:90446] " deivid.rodriguez
  11 siblings, 0 replies; 12+ messages in thread
From: deivid.rodriguez @ 2018-12-11 22:20 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by deivid (David Rodríguez).


Hello! I have very similar views to alanwu.

The original proposal of extending the API to be able to distinguish between regular method calls and tail calls sounds good to me in principle and looks like it would solve the problem in the general case. It would be a niche feature, but tailcall optimization is a niche feature too, right? It just happens to be used in a standard lib method, that's why it's biting byebug.

Regarding koichi's first proposal, it's not bad either. The `return_value` method in return events is only marginally used in byebug, so it's not a big deal to lose it on these egde cases.

Regarding koichi's last proposal.. Again I agree with alanwu. Couldn't using the tracepoint API over programs relying on tailcall optimization actually break those programs?

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75581

* Author: alanwu (Alan Wu)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.


---Files--------------------------------
no-tco-no-problem.patch (520 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90437] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (9 preceding siblings ...)
  2018-12-11 22:20 ` [ruby-core:90428] " deivid.rodriguez
@ 2018-12-12  6:06 ` ko1
  2018-12-12 12:07 ` [ruby-core:90446] " deivid.rodriguez
  11 siblings, 0 replies; 12+ messages in thread
From: ko1 @ 2018-12-12  6:06 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by ko1 (Koichi Sasada).


Matz decided to remove tailcall opt from core libraries.
r66349 was committed by nobu.


----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75594

* Author: alanwu (Alan Wu)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.


---Files--------------------------------
no-tco-no-problem.patch (520 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [ruby-core:90446] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied
       [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
                   ` (10 preceding siblings ...)
  2018-12-12  6:06 ` [ruby-core:90437] " ko1
@ 2018-12-12 12:07 ` deivid.rodriguez
  11 siblings, 0 replies; 12+ messages in thread
From: deivid.rodriguez @ 2018-12-12 12:07 UTC (permalink / raw)
  To: ruby-core

Issue #15303 has been updated by deivid (David Rodríguez).


Thank you! That works for me too, and will solve the majority of the cases :)

----------------------------------------
Bug #15303: Return tracepoint doesn't fire when tailcall optimization is applied
https://bugs.ruby-lang.org/issues/15303#change-75606

* Author: alanwu (Alan Wu)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.0dev (2018-11-14 trunk 65727) [x86_64-darwin17]
* Backport: 2.3: UNKNOWN, 2.4: UNKNOWN, 2.5: UNKNOWN
----------------------------------------
After a tailcall, the "return" tracepoint event is only fired once. Normally, after a call at the end of a method, the return event is fired twice, once for the callee returning and once for the caller returning.
The following script outputs 
~~~
:call
:call
:call
:return
~~~

~~~ ruby
method_source = <<-RB
def toy(n)
   return if n == 2
   toy(n+1)
end
RB

iseq = RubyVM::InstructionSequence.compile(method_source, tailcall_optimization: true)
#puts iseq.disasm
iseq.eval

trace = TracePoint.new(:call, :return) do |tp|
    p tp.event
end

trace.enable
toy(0)
~~~

The "return" event behaves more like a "stack frame pop" event currently. I don't think it's feasible/desirable to have the same behavior when TCO is applied, but it would be nice if there was some way for the tracepoint to know a tail call is going to happen.
I'm raising this issue because the popular debugger "byebug" relies on these events to track execution in various stack frames. https://github.com/deivid-rodriguez/byebug/issues/481
Forwardable explicitly uses TCO which triggers this issue.


---Files--------------------------------
no-tco-no-problem.patch (520 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-12-12 12:07 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-15303.20181114191300@ruby-lang.org>
2018-11-14 19:13 ` [ruby-core:89797] [Ruby trunk Bug#15303] Return tracepoint doesn't fire when tailcall optimization is applied alanwucanada
2018-12-05  7:03 ` [ruby-core:90300] " ko1
2018-12-05 15:50 ` [ruby-core:90317] " alanwucanada
2018-12-05 16:33 ` [ruby-core:90318] " ko1
2018-12-05 16:50 ` [ruby-core:90319] " alanwucanada
2018-12-05 17:02 ` [ruby-core:90321] " ko1
2018-12-05 17:19 ` [ruby-core:90323] " alanwucanada
2018-12-08  1:31 ` [ruby-core:90376] " ko1
2018-12-08  6:33 ` [ruby-core:90377] " alanwucanada
2018-12-11 22:20 ` [ruby-core:90428] " deivid.rodriguez
2018-12-12  6:06 ` [ruby-core:90437] " ko1
2018-12-12 12:07 ` [ruby-core:90446] " deivid.rodriguez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).