forwardable.rb: adjust backtrace by tail call

* lib/forwardable.rb (def_instance_delegator): adjust backtrace of
  method body by tail call optimization.  adjusting the delegated
  target is still done by deleting backtrace.
* lib/forwardable.rb (def_single_delegator): ditto.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53383 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2015-12-30 02:28:59 +00:00
Родитель d8eb5ade4f
Коммит 6fd18ca51b
3 изменённых файлов: 38 добавлений и 18 удалений

Просмотреть файл

@ -1,3 +1,11 @@
Wed Dec 30 11:28:57 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/forwardable.rb (def_instance_delegator): adjust backtrace of
method body by tail call optimization. adjusting the delegated
target is still done by deleting backtrace.
* lib/forwardable.rb (def_single_delegator): ditto.
Wed Dec 30 11:18:42 2015 Elliot Winkler <elliot.winkler@gmail.com>
* lib/forwardable.rb (def_instance_delegator) fix delegating to

Просмотреть файл

@ -182,23 +182,28 @@ module Forwardable
accessor = "#{accessor}()"
end
line_no = __LINE__; str = %{
line_no = __LINE__; str = %{proc do
def #{ali}(*args, &block)
begin
#{accessor}.__send__(:#{method}, *args, &block)
rescue ::Exception
$@.delete_if{|s| ::Forwardable::FILE_REGEXP =~ s} unless ::Forwardable::debug
::Kernel::raise
end
#{accessor}
ensure
$@.delete_if {|s| ::Forwardable::FILE_REGEXP =~ s} if $@ and !::Forwardable::debug
end.__send__(:#{method}, *args, &block)
end
}
end}
gen = RubyVM::InstructionSequence
.compile(str, __FILE__, __FILE__, line_no,
trace_instruction: false,
tailcall_optimization: true)
.eval
# If it's not a class or module, it's an instance
begin
module_eval(str, __FILE__, line_no)
module_eval(&gen)
rescue
instance_eval(str, __FILE__, line_no)
instance_eval(&gen)
end
end
alias delegate instance_delegate
@ -278,18 +283,23 @@ module SingleForwardable
accessor = "#{accessor}()"
end
line_no = __LINE__; str = %{
line_no = __LINE__; str = %{proc do
def #{ali}(*args, &block)
begin
#{accessor}.__send__(:#{method}, *args, &block)
rescue ::Exception
$@.delete_if{|s| ::Forwardable::FILE_REGEXP =~ s} unless ::Forwardable::debug
::Kernel::raise
end
#{accessor}
ensure
$@.delete_if {|s| ::Forwardable::FILE_REGEXP =~ s} if $@ and !::Forwardable::debug
end.__send__(:#{method}, *args, &block)
end
}
end}
instance_eval(str, __FILE__, line_no)
gen = RubyVM::InstructionSequence
.compile(str, __FILE__, __FILE__, line_no,
trace_instruction: false,
tailcall_optimization: true)
.eval
instance_eval(&gen)
end
alias delegate single_delegate

Просмотреть файл

@ -187,6 +187,7 @@ class TestForwardable < Test::Unit::TestCase
extend Forwardable
def_delegator :bar, :baz
def_delegator :caller, :itself, :c
class Exception
end
@ -197,6 +198,7 @@ class TestForwardable < Test::Unit::TestCase
Foo.new.baz
}
assert_not_match(/\/forwardable\.rb/, e.backtrace[0])
assert_equal(caller(0, 1)[0], Foo.new.c[0])
end
class Foo2 < BasicObject