Permalink
Browse files

Cleanup backtraces, add Exception#capture_backtrace!

This adds a new protocol used to fill the backtrace that subclasses can
override if they wish.

Also, custom backtraces (Array of Strings) are better support and don't
master a true Backtrace object ever.
  • Loading branch information...
Evan Phoenix
Evan Phoenix committed Feb 9, 2010
1 parent c40a935 commit 274fd73248512876d89acedb9d2d33eecb4e3356
Showing with 71 additions and 17 deletions.
  1. +2 −3 kernel/bootstrap/exception.rb
  2. +28 −2 kernel/common/backtrace.rb
  3. +34 −9 kernel/common/exception.rb
  4. +6 −0 kernel/delta/exception.rb
  5. +1 −3 kernel/delta/kernel.rb
@@ -1,6 +1,5 @@
class Exception
def fill_locations
Ruby.primitive :exception_fill_locations
raise PrimitiveFailure, "Unable to fill locations"
def capture_backtrace!(offset)
# replaced in delta with a real implementation
end
end
View
@@ -31,6 +31,8 @@ def initialize(locations)
@inline_effect = "\033[0;4m"
@width = Rubinius::TERMINAL_WIDTH
@mri_backtrace = nil
end
def [](index)
@@ -157,11 +159,35 @@ def each
self
end
def self.detect_backtrace(obj)
if bt = obj.instance_variable_get(:@rbx_backtrace)
return bt if bt.same_mri_backtrace?(obj)
end
return nil
end
# HACK: This should be MRI compliant-ish. --rue
#
def to_mri()
@locations.map do |loc|
def to_mri
return @mri_backtrace if @mri_backtrace
@mri_backtrace = @locations.map do |loc|
"#{loc.position}:in `#{loc.describe_method}'"
end
# A little extra magic, so we can carry the backtrace along and reuse it
@mri_backtrace.instance_variable_set(:@rbx_backtrace, self)
return @mri_backtrace
end
def same_mri_backtrace?(obj)
currently = @locations.map do |loc|
"#{loc.position}:in `#{loc.describe_method}'"
end
currently == obj
end
end
View
@@ -8,20 +8,15 @@ def initialize(message = nil)
@message = message
@locations = nil
@backtrace = nil
@custom_backtrace = nil
end
# Needed to properly implement #exception, which must clone and call
# #initialize again, BUT not a subclasses initialize.
alias_method :__initialize__, :initialize
def backtrace
if @backtrace
if @backtrace.kind_of? Array
return @backtrace
end
return @backtrace.to_mri
end
return @custom_backtrace if @custom_backtrace
if @locations
awesome_backtrace.to_mri
@@ -30,19 +25,40 @@ def backtrace
end
end
# Indicates if the Exception has a backtrace set
def backtrace?
(@backtrace || @locations) ? true : false
end
def awesome_backtrace
@backtrace = Backtrace.backtrace(@locations)
@backtrace ||= Backtrace.backtrace(@locations)
end
def render(header="An exception occurred", io=STDOUT)
io.puts header
io.puts " #{message} (#{self.class})"
if @custom_backtrace
io.puts "\nUser defined backtrace:"
@custom_backtrace.each do |line|
io.puts " #{line}"
end
end
io.puts "\nBacktrace:"
io.puts awesome_backtrace.show
extra = @parent
while extra
io.puts "\nCaused by: #{extra.message} (#{extra.class})"
if @custom_backtrace
io.puts "\nUser defined backtrace:"
@custom_backtrace.each do |line|
io.puts " #{line}"
end
end
io.puts "\nBacktrace:"
io.puts extra.awesome_backtrace.show
@@ -52,7 +68,16 @@ def render(header="An exception occurred", io=STDOUT)
end
def set_backtrace(bt)
@backtrace = bt
if bt.kind_of? Backtrace
@backtrace = bt
else
# See if we stashed a Backtrace object away, and use it.
if hidden_bt = Backtrace.detect_backtrace(bt)
@backtrace = hidden_bt
else
@custom_backtrace = bt
end
end
end
def set_context(ctx)
@@ -9,3 +9,9 @@
class FatalError < Exception
end
class Exception
def capture_backtrace!(offset=1)
@locations = Rubinius::VM.backtrace offset
end
end
View
@@ -30,9 +30,7 @@ def raise(exc=undefined, msg=undefined, ctx=nil)
unless skip
exc.set_context ctx if ctx
unless exc.locations
exc.locations = Rubinius::VM.backtrace 1
end
exc.capture_backtrace!(2) unless exc.backtrace?
end
if $DEBUG and $VERBOSE != nil

0 comments on commit 274fd73

Please sign in to comment.