Class: Pf2::Reporter::StackWeaver
- Inherits:
-
Object
- Object
- Pf2::Reporter::StackWeaver
- Defined in:
- lib/pf2/reporter/stack_weaver.rb
Overview
“Weaves” the native stack into the Ruby stack.
Strategy:
-
Split the stack into Ruby and Native parts
-
Start from the root of the Native stack
-
Dig in to the native stack until we hit a rb_vm_exec(), which marks a call into Ruby code
-
Switch to Ruby stack. Keep digging until we hit a Cfunc call, then switch back to Native stack
-
Repeat until we consume the entire stack
Instance Method Summary collapse
-
#initialize(profile) ⇒ StackWeaver
constructor
A new instance of StackWeaver.
- #should_switch_to_native?(location_index, native_stack_remainder) ⇒ Boolean
- #should_switch_to_ruby?(location_index) ⇒ Boolean
- #weave(ruby_stack, native_stack) ⇒ Object
Constructor Details
#initialize(profile) ⇒ StackWeaver
Returns a new instance of StackWeaver.
14 15 16 |
# File 'lib/pf2/reporter/stack_weaver.rb', line 14 def initialize(profile) @profile = profile end |
Instance Method Details
#should_switch_to_native?(location_index, native_stack_remainder) ⇒ Boolean
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/pf2/reporter/stack_weaver.rb', line 57 def should_switch_to_native?(location_index, native_stack_remainder) location = @profile[:locations][location_index] function = @profile[:functions][location[:function_index]] raise if function[:implementation] != :ruby # assert # Is the current Ruby function a cfunc? return false if function[:start_address] == nil # Does a corresponding native function exist in the remainder of the native stack? loop do break if native_stack_remainder.size == 0 n_location_index = native_stack_remainder.pop n_location = @profile[:locations][n_location_index] n_function = @profile[:functions][n_location[:function_index]] return true if function[:start_address] == n_function[:start_address] end false end |
#should_switch_to_ruby?(location_index) ⇒ Boolean
78 79 80 81 82 83 84 85 86 |
# File 'lib/pf2/reporter/stack_weaver.rb', line 78 def should_switch_to_ruby?(location_index) location = @profile[:locations][location_index] function = @profile[:functions][location[:function_index]] raise if function[:implementation] != :native # assert # If the next function is a vm_exec_core() (= VM_EXEC in vm_exec.h), # we switch to the Ruby stack. function[:name] == 'vm_exec_core' end |
#weave(ruby_stack, native_stack) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/pf2/reporter/stack_weaver.rb', line 18 def weave(ruby_stack, native_stack) ruby_stack = ruby_stack.dup native_stack = native_stack.dup weaved_stack = [] current_stack = :native loop do break if ruby_stack.size == 0 && native_stack.size == 0 case current_stack when :ruby if ruby_stack.size == 0 # We've reached the end of the Ruby stack current_stack = :native next end location_index = ruby_stack.pop weaved_stack.unshift(location_index) current_stack = :native if should_switch_to_native?(location_index, native_stack.dup) when :native if native_stack.size == 0 # We've reached the end of the native stack current_stack = :ruby next end location_index = native_stack.pop weaved_stack.unshift(location_index) current_stack = :ruby if should_switch_to_ruby?(location_index) end end weaved_stack end |