Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add support for nested exceptions.

  • Loading branch information...
commit 243efc4e16f3dcd40c1734e934be62318cdf825b 1 parent b016970
@whitequark authored
View
2  lib/furnace-avm2.rb
@@ -10,5 +10,7 @@ module Furnace::AVM2
require "furnace-avm2/version"
+require "furnace-avm2/range_extensions"
+
require "furnace-avm2/abc"
require "furnace-avm2/transform"
View
12 lib/furnace-avm2/range_extensions.rb
@@ -0,0 +1,12 @@
+class Range
+ def intersection(other)
+ raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)
+
+ new_min = self.cover?(other.min) ? other.min : other.cover?(min) ? min : nil
+ new_max = self.cover?(other.max) ? other.max : other.cover?(max) ? max : nil
+
+ new_min && new_max ? new_min..new_max : nil
+ end
+
+ alias_method :&, :intersection
+end
View
31 lib/furnace-avm2/transform/cfg_build.rb
@@ -28,6 +28,37 @@ def transform(code, body)
exc.target_offset ])
end
+ # Handle nested exception handling blocks.
+
+ exceptions_within = Hash.new { |h,k| h[k] = Set[] }
+
+ @exceptions = Hash[
+ @exceptions.sort do |(left_range, left), (right_range, right)|
+ intersection = (left_range & right_range)
+ if intersection.nil?
+ 0
+ elsif intersection == left_range
+ exceptions_within[left].add right
+ -1
+ elsif intersection == right_range
+ exceptions_within[right].add left
+ 1
+ else
+ raise "impossible exception handler layout"
+ end
+ end
+ ]
+
+ # Set nearest outermost exception handler.
+
+ @exceptions.each do |range, inner|
+ if exceptions_within[inner].any?
+ inner.exception_label = @exceptions.values.find do |outer|
+ exceptions_within[inner].include? outer
+ end.label
+ end
+ end
+
@pending_label = nil
@pending_exc_block = nil
@pending_exc_range = nil
View
13 lib/furnace-avm2/transform/cfg_reduce.rb
@@ -51,7 +51,7 @@ def possibly_wrap_eh(block, nodes, exception, loop_stack, nesting)
root, *tails = find_merge_point([ block ] + exception.targets)
exception.targets.zip(tails).each_with_index do |(target, tail), index|
log nesting, "handler #{catches[index].inspect}"
- handler = extended_block(target, tail || root, loop_stack, nesting + 1, nil)
+ handler = extended_block(target, tail || root, loop_stack, nesting + 1, exception.exception)
node = catches[index]
if node.type == :catch
@@ -119,10 +119,10 @@ def extended_block(block, stopgap=nil, loop_stack=[], nesting=0, upper_exc=nil,
current_nodes = []
exception_changed = false
- log nesting, "--- STOPGAP: #{stopgap.inspect}"
+ log nesting, "--- STOPGAP: #{stopgap.label.inspect}" if stopgap
while block
- log nesting, "BLOCK: #{block.inspect}"
+ log nesting, "BLOCK: #{block.label.inspect}"
if is_loop_head?(block, loop_stack)
if options[:infinite_loop_head]
@@ -172,7 +172,12 @@ def extended_block(block, stopgap=nil, loop_stack=[], nesting=0, upper_exc=nil,
"NEW-EX: #{(block.exception.label if block.exception) || '-'}"
if block.exception != current_exception
- nodes.concat possibly_wrap_eh(prev_block, current_nodes, current_exception, loop_stack, nesting)
+ # Don't wrap with a handler if we're coming within
+ # a nested scope.
+ unless block.exception && current_exception &&
+ block.exception.exception == current_exception
+ nodes.concat possibly_wrap_eh(prev_block, current_nodes, current_exception, loop_stack, nesting)
+ end
current_exception = block.exception
current_nodes = []
Please sign in to comment.
Something went wrong with that request. Please try again.