Skip to content

Commit

Permalink
Cleanup backtraces, add Exception#capture_backtrace!
Browse files Browse the repository at this point in the history
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 committed Feb 9, 2010
1 parent c40a935 commit 274fd73
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 17 deletions.
5 changes: 2 additions & 3 deletions kernel/bootstrap/exception.rb
Original file line number Diff line number Diff line change
@@ -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
30 changes: 28 additions & 2 deletions kernel/common/backtrace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def initialize(locations)
@inline_effect = "\033[0;4m"

@width = Rubinius::TERMINAL_WIDTH

@mri_backtrace = nil
end

def [](index)
Expand Down Expand Up @@ -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
43 changes: 34 additions & 9 deletions kernel/common/exception.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions kernel/delta/exception.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@

class FatalError < Exception
end

class Exception
def capture_backtrace!(offset=1)
@locations = Rubinius::VM.backtrace offset
end
end
4 changes: 1 addition & 3 deletions kernel/delta/kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 274fd73

Please sign in to comment.