mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	use builtin for TracePoint.
Define TracePoint in trace_point.rb and use __builtin_ syntax.
This commit is contained in:
		
							parent
							
								
									46acd0075d
								
							
						
					
					
						commit
						e2a45cb984
					
				
				
				Notes:
				
					git
				
				2019-11-08 09:10:08 +09:00 
				
			
			
			
		
		
					 8 changed files with 527 additions and 438 deletions
				
			
		| 
						 | 
				
			
			@ -9,9 +9,10 @@
 | 
			
		|||
 | 
			
		||||
# prelude
 | 
			
		||||
prelude.rb
 | 
			
		||||
 | 
			
		||||
rbconfig.rb
 | 
			
		||||
 | 
			
		||||
trace_point.rb
 | 
			
		||||
 | 
			
		||||
# the lib/ directory (which has its own .document file)
 | 
			
		||||
lib
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1094,11 +1094,14 @@ preludes: {$(VPATH)}prelude.c
 | 
			
		|||
preludes: {$(VPATH)}miniprelude.c
 | 
			
		||||
preludes: {$(srcdir)}golf_prelude.c
 | 
			
		||||
 | 
			
		||||
BUILTIN_RB_SRCS =
 | 
			
		||||
BUILTIN_RB_SRCS = $(srcdir)/trace_point.rb
 | 
			
		||||
 | 
			
		||||
builtin_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/tool/mk_builtin_binary.rb
 | 
			
		||||
	$(Q) $(MINIRUBY) $(srcdir)/tool/mk_builtin_binary.rb
 | 
			
		||||
 | 
			
		||||
load_trace_point.inc: $(srcdir)/trace_point.rb $(srcdir)/tool/mk_builtin_loader.rb
 | 
			
		||||
	$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/trace_point.rb
 | 
			
		||||
 | 
			
		||||
$(srcdir)/revision.h:
 | 
			
		||||
	$(Q)$(gnumake:yes=#) $(RM) $(@F)
 | 
			
		||||
	$(Q)$(gnumake:yes=#) exit > $@ || exit > $(@F)
 | 
			
		||||
| 
						 | 
				
			
			@ -3389,6 +3392,7 @@ vm_trace.$(OBJEXT): $(CCAN_DIR)/str/str.h
 | 
			
		|||
vm_trace.$(OBJEXT): $(hdrdir)/ruby.h
 | 
			
		||||
vm_trace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}assert.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}builtin.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}config.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}debug.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}debug_counter.h
 | 
			
		||||
| 
						 | 
				
			
			@ -3400,6 +3404,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}intern.h
 | 
			
		|||
vm_trace.$(OBJEXT): {$(VPATH)}internal.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}io.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}iseq.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}load_trace_point.inc
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}method.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}missing.h
 | 
			
		||||
vm_trace.$(OBJEXT): {$(VPATH)}mjit.h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								inits.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								inits.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -65,11 +65,12 @@ rb_call_inits(void)
 | 
			
		|||
    CALL(Rational);
 | 
			
		||||
    CALL(Complex);
 | 
			
		||||
    CALL(version);
 | 
			
		||||
    CALL(vm_trace);
 | 
			
		||||
    CALL(vm_stack_canary);
 | 
			
		||||
    CALL(ast);
 | 
			
		||||
    CALL(gc_stress);
 | 
			
		||||
 | 
			
		||||
    CALL(builtin);
 | 
			
		||||
 | 
			
		||||
    CALL(vm_trace);
 | 
			
		||||
}
 | 
			
		||||
#undef CALL
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								prelude.rb
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								prelude.rb
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -136,69 +136,6 @@ class IO
 | 
			
		|||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class TracePoint
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #    trace.enable(target: nil, target_line: nil, target_thread: nil)    -> true or false
 | 
			
		||||
  #    trace.enable(target: nil, target_line: nil, target_thread: nil) { block }  -> obj
 | 
			
		||||
  #
 | 
			
		||||
  # Activates the trace.
 | 
			
		||||
  #
 | 
			
		||||
  # Returns +true+ if trace was enabled.
 | 
			
		||||
  # Returns +false+ if trace was disabled.
 | 
			
		||||
  #
 | 
			
		||||
  #   trace.enabled?  #=> false
 | 
			
		||||
  #   trace.enable    #=> false (previous state)
 | 
			
		||||
  #                   #   trace is enabled
 | 
			
		||||
  #   trace.enabled?  #=> true
 | 
			
		||||
  #   trace.enable    #=> true (previous state)
 | 
			
		||||
  #                   #   trace is still enabled
 | 
			
		||||
  #
 | 
			
		||||
  # If a block is given, the trace will only be enabled within the scope of the
 | 
			
		||||
  # block.
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enabled?
 | 
			
		||||
  #    #=> false
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enable do
 | 
			
		||||
  #      trace.enabled?
 | 
			
		||||
  #      # only enabled for this block
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enabled?
 | 
			
		||||
  #    #=> false
 | 
			
		||||
  #
 | 
			
		||||
  # +target+, +target_line+ and +target_thread+ parameters are used to
 | 
			
		||||
  # limit tracing only to specified code objects. +target+ should be a
 | 
			
		||||
  # code object for which RubyVM::InstructionSequence.of will return
 | 
			
		||||
  # an instruction sequence.
 | 
			
		||||
  #
 | 
			
		||||
  #    t = TracePoint.new(:line) { |tp| p tp }
 | 
			
		||||
  #
 | 
			
		||||
  #    def m1
 | 
			
		||||
  #      p 1
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    def m2
 | 
			
		||||
  #      p 2
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    t.enable(target: method(:m1))
 | 
			
		||||
  #
 | 
			
		||||
  #    m1
 | 
			
		||||
  #    # prints #<TracePoint:line@test.rb:5 in `m1'>
 | 
			
		||||
  #    m2
 | 
			
		||||
  #    # prints nothing
 | 
			
		||||
  #
 | 
			
		||||
  # Note: You cannot access event hooks within the +enable+ block.
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enable { p tp.lineno }
 | 
			
		||||
  #    #=> RuntimeError: access from outside
 | 
			
		||||
  #
 | 
			
		||||
  def enable target: nil, target_line: nil, target_thread: nil, &blk
 | 
			
		||||
    self.__enable target, target_line, target_thread, &blk
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Binding
 | 
			
		||||
  # :nodoc:
 | 
			
		||||
  def irb
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -466,6 +466,130 @@ class TestSetTraceFunc < Test::Unit::TestCase
 | 
			
		|||
      trace.disable if trace&.enabled?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    answer_events = [
 | 
			
		||||
     #
 | 
			
		||||
     [:line,     4, 'xyzzy', self.class,  method,           self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,   4, 'xyzzy', Integer,     :times,           1,           :outer, :nothing],
 | 
			
		||||
     [:line,     4, 'xyzzy', self.class,  method,           self,        nil,    :nothing],
 | 
			
		||||
     [:line,     5, 'xyzzy', self.class,  method,           self,        :inner, :nothing],
 | 
			
		||||
     [:c_call,   5, 'xyzzy', Kernel,      :tap,             self,        :inner, :nothing],
 | 
			
		||||
     [:c_return, 5, "xyzzy", Kernel,      :tap,             self,        :inner, self],
 | 
			
		||||
     [:c_return, 4, "xyzzy", Integer,     :times,           1,           :outer, 1],
 | 
			
		||||
     [:line,     7, 'xyzzy', self.class,  method,           self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,   7, "xyzzy", Class,       :inherited,       Object,      :outer, :nothing],
 | 
			
		||||
     [:c_return, 7, "xyzzy", Class,       :inherited,       Object,      :outer, nil],
 | 
			
		||||
     [:class,    7, "xyzzy", nil,         nil,              xyzzy.class, nil,    :nothing],
 | 
			
		||||
     [:line,     8, "xyzzy", nil,         nil,              xyzzy.class, nil,    :nothing],
 | 
			
		||||
     [:line,     9, "xyzzy", nil,         nil,              xyzzy.class, :XYZZY_outer, :nothing],
 | 
			
		||||
     [:c_call,   9, "xyzzy", Module,      :method_added,    xyzzy.class, :XYZZY_outer, :nothing],
 | 
			
		||||
     [:c_return, 9, "xyzzy", Module,      :method_added,    xyzzy.class, :XYZZY_outer, nil],
 | 
			
		||||
     [:line,    13, "xyzzy", nil,         nil,              xyzzy.class, :XYZZY_outer, :nothing],
 | 
			
		||||
     [:c_call,  13, "xyzzy", Module,      :method_added,    xyzzy.class, :XYZZY_outer, :nothing],
 | 
			
		||||
     [:c_return,13, "xyzzy", Module,      :method_added,    xyzzy.class, :XYZZY_outer, nil],
 | 
			
		||||
     [:end,     17, "xyzzy", nil,         nil,              xyzzy.class, :XYZZY_outer, :nothing],
 | 
			
		||||
     [:line,    18, "xyzzy", TestSetTraceFunc, method,      self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,  18, "xyzzy", Class,       :new,             xyzzy.class, :outer, :nothing],
 | 
			
		||||
     [:c_call,  18, "xyzzy", BasicObject, :initialize,      xyzzy,       :outer, :nothing],
 | 
			
		||||
     [:c_return,18, "xyzzy", BasicObject, :initialize,      xyzzy,       :outer, nil],
 | 
			
		||||
     [:c_return,18, "xyzzy", Class,       :new,             xyzzy.class, :outer, xyzzy],
 | 
			
		||||
     [:line,    19, "xyzzy", TestSetTraceFunc, method,      self, :outer, :nothing],
 | 
			
		||||
     [:call,     9, "xyzzy", xyzzy.class, :foo,             xyzzy,       nil,  :nothing],
 | 
			
		||||
     [:line,    10, "xyzzy", xyzzy.class, :foo,             xyzzy,       nil,  :nothing],
 | 
			
		||||
     [:line,    11, "xyzzy", xyzzy.class, :foo,             xyzzy,       :XYZZY_foo, :nothing],
 | 
			
		||||
     [:call,    13, "xyzzy", xyzzy.class, :bar,             xyzzy,       nil, :nothing],
 | 
			
		||||
     [:line,    14, "xyzzy", xyzzy.class, :bar,             xyzzy,       nil, :nothing],
 | 
			
		||||
     [:line,    15, "xyzzy", xyzzy.class, :bar,             xyzzy,       :XYZZY_bar, :nothing],
 | 
			
		||||
     [:c_call,  15, "xyzzy", Kernel,      :tap,             xyzzy,       :XYZZY_bar, :nothing],
 | 
			
		||||
     [:c_return,15, "xyzzy", Kernel,      :tap,             xyzzy,       :XYZZY_bar, xyzzy],
 | 
			
		||||
     [:return,  16, "xyzzy", xyzzy.class, :bar,             xyzzy,       :XYZZY_bar, xyzzy],
 | 
			
		||||
     [:return,  12, "xyzzy", xyzzy.class, :foo,             xyzzy,       :XYZZY_foo, xyzzy],
 | 
			
		||||
     [:line,    20, "xyzzy", TestSetTraceFunc, method,      self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,  20, "xyzzy", Kernel,      :raise,           self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,  20, "xyzzy", Exception,   :exception,       RuntimeError, :outer, :nothing],
 | 
			
		||||
     [:c_call,  20, "xyzzy", Exception,   :initialize,      raised_exc,  :outer, :nothing],
 | 
			
		||||
     [:c_return,20, "xyzzy", Exception,   :initialize,      raised_exc,  :outer, raised_exc],
 | 
			
		||||
     [:c_return,20, "xyzzy", Exception,   :exception,       RuntimeError, :outer, raised_exc],
 | 
			
		||||
     [:c_return,20, "xyzzy", Kernel,      :raise,           self,        :outer, nil],
 | 
			
		||||
     [:c_call,  20, "xyzzy", Exception,   :backtrace,       raised_exc,  :outer, :nothing],
 | 
			
		||||
     [:c_return,20, "xyzzy", Exception,   :backtrace,       raised_exc,  :outer, nil],
 | 
			
		||||
     [:raise,   20, "xyzzy", TestSetTraceFunc, :trace_by_tracepoint, self, :outer, raised_exc],
 | 
			
		||||
     [:c_call,  20, "xyzzy", Module,      :===,             RuntimeError,:outer, :nothing],
 | 
			
		||||
     [:c_return,20, "xyzzy", Module,      :===,             RuntimeError,:outer, true],
 | 
			
		||||
     [:line,    21, "xyzzy", TestSetTraceFunc, method,      self,        :outer, :nothing],
 | 
			
		||||
     ]
 | 
			
		||||
 | 
			
		||||
    return events, answer_events
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_tracepoint
 | 
			
		||||
    events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise)
 | 
			
		||||
 | 
			
		||||
    ms = [events1, answer_events].map{|evs|
 | 
			
		||||
      evs.map{|e|
 | 
			
		||||
        "#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if false # show all events
 | 
			
		||||
      printf(" %-60s | %-60s\n", "actual", "expected")
 | 
			
		||||
      ms[0].zip(ms[1]){|a, b|
 | 
			
		||||
        printf("%s%-60s | %-60s\n", a==b ? ' ' : '!', a, b)
 | 
			
		||||
      }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    mesg = ms[0].zip(ms[1]).map{|a, b|
 | 
			
		||||
      if a != b
 | 
			
		||||
        "actual: #{a} <-> expected: #{b}"
 | 
			
		||||
      end
 | 
			
		||||
    }.compact.join("\n")
 | 
			
		||||
 | 
			
		||||
    answer_events.zip(events1){|answer, event|
 | 
			
		||||
      assert_equal answer, event, mesg
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [:line, :class, :end, :call, :return, :c_call, :c_return, :raise].each{|event|
 | 
			
		||||
      events1, answer_events = *trace_by_tracepoint(event)
 | 
			
		||||
      answer_events.find_all{|e| e[0] == event}.zip(events1){|answer_line, event_line|
 | 
			
		||||
        assert_equal answer_line, event_line
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def trace_by_set_trace_func
 | 
			
		||||
    events = []
 | 
			
		||||
    trace = nil
 | 
			
		||||
    trace = trace
 | 
			
		||||
    xyzzy = nil
 | 
			
		||||
    xyzzy = xyzzy
 | 
			
		||||
    _local_var = :outer
 | 
			
		||||
    method = :trace_by_set_trace_func
 | 
			
		||||
    raised_exc = nil
 | 
			
		||||
 | 
			
		||||
    eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy'
 | 
			
		||||
    1: set_trace_func(lambda{|event, file, line, id, binding, klass|
 | 
			
		||||
    2:   events << [event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")] if file == 'xyzzy'
 | 
			
		||||
    3: })
 | 
			
		||||
    4: 1.times{|;_local_var| _local_var = :inner
 | 
			
		||||
    5:   tap{}
 | 
			
		||||
    6: }
 | 
			
		||||
    7: class XYZZY
 | 
			
		||||
    8:   _local_var = :XYZZY_outer
 | 
			
		||||
    9:   def foo
 | 
			
		||||
   10:     _local_var = :XYZZY_foo
 | 
			
		||||
   11:     bar
 | 
			
		||||
   12:   end
 | 
			
		||||
   13:   def bar
 | 
			
		||||
   14:     _local_var = :XYZZY_bar
 | 
			
		||||
   15:     tap{}
 | 
			
		||||
   16:   end
 | 
			
		||||
   17: end
 | 
			
		||||
   18: xyzzy = XYZZY.new
 | 
			
		||||
   19: xyzzy.foo
 | 
			
		||||
   20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end
 | 
			
		||||
   21: set_trace_func(nil)
 | 
			
		||||
    EOF
 | 
			
		||||
    self.class.class_eval{remove_const(:XYZZY)}
 | 
			
		||||
 | 
			
		||||
    answer_events = [
 | 
			
		||||
     #
 | 
			
		||||
     [:c_return, 1, "xyzzy", TracePoint,  :trace,           TracePoint,  :outer,  trace],
 | 
			
		||||
| 
						 | 
				
			
			@ -519,79 +643,19 @@ class TestSetTraceFunc < Test::Unit::TestCase
 | 
			
		|||
     [:line,    21, "xyzzy", TestSetTraceFunc, method,      self,        :outer, :nothing],
 | 
			
		||||
     [:c_call,  21, "xyzzy", TracePoint,  :disable,         trace,       :outer, :nothing],
 | 
			
		||||
     ]
 | 
			
		||||
 | 
			
		||||
    return events, answer_events
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def trace_by_set_trace_func
 | 
			
		||||
    events = []
 | 
			
		||||
    trace = nil
 | 
			
		||||
    trace = trace
 | 
			
		||||
    xyzzy = nil
 | 
			
		||||
    xyzzy = xyzzy
 | 
			
		||||
    _local_var = :outer
 | 
			
		||||
    eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy'
 | 
			
		||||
    1: set_trace_func(lambda{|event, file, line, id, binding, klass|
 | 
			
		||||
    2:   events << [event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")] if file == 'xyzzy'
 | 
			
		||||
    3: })
 | 
			
		||||
    4: 1.times{|;_local_var| _local_var = :inner
 | 
			
		||||
    5:   tap{}
 | 
			
		||||
    6: }
 | 
			
		||||
    7: class XYZZY
 | 
			
		||||
    8:   _local_var = :XYZZY_outer
 | 
			
		||||
    9:   def foo
 | 
			
		||||
   10:     _local_var = :XYZZY_foo
 | 
			
		||||
   11:     bar
 | 
			
		||||
   12:   end
 | 
			
		||||
   13:   def bar
 | 
			
		||||
   14:     _local_var = :XYZZY_bar
 | 
			
		||||
   15:     tap{}
 | 
			
		||||
   16:   end
 | 
			
		||||
   17: end
 | 
			
		||||
   18: xyzzy = XYZZY.new
 | 
			
		||||
   19: xyzzy.foo
 | 
			
		||||
   20: begin; raise RuntimeError; rescue RuntimeError => raised_exc; end
 | 
			
		||||
   21: set_trace_func(nil)
 | 
			
		||||
    EOF
 | 
			
		||||
    self.class.class_eval{remove_const(:XYZZY)}
 | 
			
		||||
    return events
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_tracepoint
 | 
			
		||||
    events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise)
 | 
			
		||||
 | 
			
		||||
    ms = [events1, answer_events].map{|evs|
 | 
			
		||||
      evs.map{|e|
 | 
			
		||||
        "#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mesg = ms[0].zip(ms[1]).map{|a, b|
 | 
			
		||||
      if a != b
 | 
			
		||||
        "#{a} <-> #{b}"
 | 
			
		||||
      end
 | 
			
		||||
    }.compact.join("\n")
 | 
			
		||||
 | 
			
		||||
    answer_events.zip(events1){|answer, event|
 | 
			
		||||
      assert_equal answer, event, mesg
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    events2 = trace_by_set_trace_func
 | 
			
		||||
    events1.zip(events2){|ev1, ev2|
 | 
			
		||||
      ev2[0] = ev2[0].sub('-', '_').to_sym
 | 
			
		||||
      assert_equal ev1[0..2], ev2[0..2], ev1.inspect
 | 
			
		||||
  def test_set_trace_func
 | 
			
		||||
    actual_events, expected_events = trace_by_set_trace_func
 | 
			
		||||
    expected_events.zip(actual_events){|e, a|
 | 
			
		||||
      a[0] = a[0].to_s.sub('-', '_').to_sym
 | 
			
		||||
      assert_equal e[0..2], a[0..2], a.inspect
 | 
			
		||||
 | 
			
		||||
      # event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")
 | 
			
		||||
      assert_equal ev1[3].nil?, ev2[3].nil? # klass
 | 
			
		||||
      assert_equal ev1[4].nil?, ev2[4].nil? # id
 | 
			
		||||
      assert_equal ev1[6], ev2[6]           # _local_var
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [:line, :class, :end, :call, :return, :c_call, :c_return, :raise].each{|event|
 | 
			
		||||
      events1, answer_events = *trace_by_tracepoint(event)
 | 
			
		||||
      answer_events.find_all{|e| e[0] == event}.zip(events1){|answer_line, event_line|
 | 
			
		||||
        assert_equal answer_line, event_line
 | 
			
		||||
      }
 | 
			
		||||
      assert_equal e[3].nil?, a[3].nil? # klass
 | 
			
		||||
      assert_equal e[4].nil?, a[4].nil? # id
 | 
			
		||||
      assert_equal e[6], a[6]           # _local_var
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -676,7 +740,7 @@ class TestSetTraceFunc < Test::Unit::TestCase
 | 
			
		|||
    }
 | 
			
		||||
    foo
 | 
			
		||||
    trace.disable
 | 
			
		||||
    assert_equal([:foo, :foo], ary)
 | 
			
		||||
    assert_equal([:foo, :disable, :foo, :disable], ary)
 | 
			
		||||
    assert_equal([], args)
 | 
			
		||||
 | 
			
		||||
    trace = TracePoint.new{}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,9 +110,8 @@ module TestParallel
 | 
			
		|||
        end
 | 
			
		||||
 | 
			
		||||
        result = Marshal.load($1.chomp.unpack("m")[0])
 | 
			
		||||
 | 
			
		||||
        assert_equal(5, result[0])
 | 
			
		||||
        assert_equal(17, result[1])
 | 
			
		||||
        assert_equal(12, result[1])
 | 
			
		||||
        assert_kind_of(Array,result[2])
 | 
			
		||||
        assert_kind_of(Array,result[3])
 | 
			
		||||
        assert_kind_of(Array,result[4])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										348
									
								
								trace_point.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								trace_point.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,348 @@
 | 
			
		|||
# loaded from vm_trace.c
 | 
			
		||||
 | 
			
		||||
# Document-class: TracePoint
 | 
			
		||||
#
 | 
			
		||||
# A class that provides the functionality of Kernel#set_trace_func in a
 | 
			
		||||
# nice Object-Oriented API.
 | 
			
		||||
#
 | 
			
		||||
# == Example
 | 
			
		||||
#
 | 
			
		||||
# We can use TracePoint to gather information specifically for exceptions:
 | 
			
		||||
#
 | 
			
		||||
#	    trace = TracePoint.new(:raise) do |tp|
 | 
			
		||||
#		p [tp.lineno, tp.event, tp.raised_exception]
 | 
			
		||||
#	    end
 | 
			
		||||
#	    #=> #<TracePoint:disabled>
 | 
			
		||||
#
 | 
			
		||||
#	    trace.enable
 | 
			
		||||
#	    #=> false
 | 
			
		||||
#
 | 
			
		||||
#	    0 / 0
 | 
			
		||||
#	    #=> [5, :raise, #<ZeroDivisionError: divided by 0>]
 | 
			
		||||
#
 | 
			
		||||
# == Events
 | 
			
		||||
#
 | 
			
		||||
# If you don't specify the type of events you want to listen for,
 | 
			
		||||
# TracePoint will include all available events.
 | 
			
		||||
#
 | 
			
		||||
# *Note* do not depend on current event set, as this list is subject to
 | 
			
		||||
# change. Instead, it is recommended you specify the type of events you
 | 
			
		||||
# want to use.
 | 
			
		||||
#
 | 
			
		||||
# To filter what is traced, you can pass any of the following as +events+:
 | 
			
		||||
#
 | 
			
		||||
# +:line+:: execute code on a new line
 | 
			
		||||
# +:class+:: start a class or module definition
 | 
			
		||||
# +:end+:: finish a class or module definition
 | 
			
		||||
# +:call+:: call a Ruby method
 | 
			
		||||
# +:return+:: return from a Ruby method
 | 
			
		||||
# +:c_call+:: call a C-language routine
 | 
			
		||||
# +:c_return+:: return from a C-language routine
 | 
			
		||||
# +:raise+:: raise an exception
 | 
			
		||||
# +:b_call+:: event hook at block entry
 | 
			
		||||
# +:b_return+:: event hook at block ending
 | 
			
		||||
# +:thread_begin+:: event hook at thread beginning
 | 
			
		||||
# +:thread_end+:: event hook at thread ending
 | 
			
		||||
# +:fiber_switch+:: event hook at fiber switch
 | 
			
		||||
# +:script_compiled+:: new Ruby code compiled (with +eval+, +load+ or +require+)
 | 
			
		||||
#
 | 
			
		||||
class TracePoint
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #	TracePoint.new(*events) { |obj| block }	    -> obj
 | 
			
		||||
  #
 | 
			
		||||
  # Returns a new TracePoint object, not enabled by default.
 | 
			
		||||
  #
 | 
			
		||||
  # Next, in order to activate the trace, you must use TracePoint#enable
 | 
			
		||||
  #
 | 
			
		||||
  #	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
  #	    p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
 | 
			
		||||
  #	end
 | 
			
		||||
  #	#=> #<TracePoint:disabled>
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.enable
 | 
			
		||||
  #	#=> false
 | 
			
		||||
  #
 | 
			
		||||
  #	puts "Hello, TracePoint!"
 | 
			
		||||
  #	# ...
 | 
			
		||||
  #	# [48, IRB::Notifier::AbstractNotifier, :printf, :call]
 | 
			
		||||
  #	# ...
 | 
			
		||||
  #
 | 
			
		||||
  # When you want to deactivate the trace, you must use TracePoint#disable
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.disable
 | 
			
		||||
  #
 | 
			
		||||
  # See TracePoint@Events for possible events and more information.
 | 
			
		||||
  #
 | 
			
		||||
  # A block must be given, otherwise an ArgumentError is raised.
 | 
			
		||||
  #
 | 
			
		||||
  # If the trace method isn't included in the given events filter, a
 | 
			
		||||
  # RuntimeError is raised.
 | 
			
		||||
  #
 | 
			
		||||
  #	TracePoint.trace(:line) do |tp|
 | 
			
		||||
  #	    p tp.raised_exception
 | 
			
		||||
  #	end
 | 
			
		||||
  #	#=> RuntimeError: 'raised_exception' not supported by this event
 | 
			
		||||
  #
 | 
			
		||||
  # If the trace method is called outside block, a RuntimeError is raised.
 | 
			
		||||
  #
 | 
			
		||||
  #      TracePoint.trace(:line) do |tp|
 | 
			
		||||
  #        $tp = tp
 | 
			
		||||
  #      end
 | 
			
		||||
  #      $tp.lineno #=> access from outside (RuntimeError)
 | 
			
		||||
  #
 | 
			
		||||
  # Access from other threads is also forbidden.
 | 
			
		||||
  #
 | 
			
		||||
  def self.new(*events)
 | 
			
		||||
    __builtin_tracepoint_new_s(events)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  #  call-seq:
 | 
			
		||||
  #    trace.inspect  -> string
 | 
			
		||||
  #
 | 
			
		||||
  #  Return a string containing a human-readable TracePoint
 | 
			
		||||
  #  status.
 | 
			
		||||
  def inspect
 | 
			
		||||
    __builtin_tracepoint_inspect
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #	TracePoint.stat -> obj
 | 
			
		||||
  #
 | 
			
		||||
  #  Returns internal information of TracePoint.
 | 
			
		||||
  #
 | 
			
		||||
  #  The contents of the returned value are implementation specific.
 | 
			
		||||
  #  It may be changed in future.
 | 
			
		||||
  #
 | 
			
		||||
  #  This method is only for debugging TracePoint itself.
 | 
			
		||||
  def stat
 | 
			
		||||
    __builtin_tracepoint_stat_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Document-method: trace
 | 
			
		||||
  #
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #	TracePoint.trace(*events) { |obj| block }	-> obj
 | 
			
		||||
  #
 | 
			
		||||
  #  A convenience method for TracePoint.new, that activates the trace
 | 
			
		||||
  #  automatically.
 | 
			
		||||
  #
 | 
			
		||||
  #	    trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] }
 | 
			
		||||
  #	    #=> #<TracePoint:enabled>
 | 
			
		||||
  #
 | 
			
		||||
  #	    trace.enabled? #=> true
 | 
			
		||||
  #
 | 
			
		||||
  def self.trace(*events)
 | 
			
		||||
    __builtin_tracepoint_trace_s(events)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #    trace.enable(target: nil, target_line: nil, target_thread: nil)    -> true or false
 | 
			
		||||
  #    trace.enable(target: nil, target_line: nil, target_thread: nil) { block }  -> obj
 | 
			
		||||
  #
 | 
			
		||||
  # Activates the trace.
 | 
			
		||||
  #
 | 
			
		||||
  # Returns +true+ if trace was enabled.
 | 
			
		||||
  # Returns +false+ if trace was disabled.
 | 
			
		||||
  #
 | 
			
		||||
  #   trace.enabled?  #=> false
 | 
			
		||||
  #   trace.enable    #=> false (previous state)
 | 
			
		||||
  #                   #   trace is enabled
 | 
			
		||||
  #   trace.enabled?  #=> true
 | 
			
		||||
  #   trace.enable    #=> true (previous state)
 | 
			
		||||
  #                   #   trace is still enabled
 | 
			
		||||
  #
 | 
			
		||||
  # If a block is given, the trace will only be enabled within the scope of the
 | 
			
		||||
  # block.
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enabled?
 | 
			
		||||
  #    #=> false
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enable do
 | 
			
		||||
  #      trace.enabled?
 | 
			
		||||
  #      # only enabled for this block
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enabled?
 | 
			
		||||
  #    #=> false
 | 
			
		||||
  #
 | 
			
		||||
  # +target+, +target_line+ and +target_thread+ parameters are used to
 | 
			
		||||
  # limit tracing only to specified code objects. +target+ should be a
 | 
			
		||||
  # code object for which RubyVM::InstructionSequence.of will return
 | 
			
		||||
  # an instruction sequence.
 | 
			
		||||
  #
 | 
			
		||||
  #    t = TracePoint.new(:line) { |tp| p tp }
 | 
			
		||||
  #
 | 
			
		||||
  #    def m1
 | 
			
		||||
  #      p 1
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    def m2
 | 
			
		||||
  #      p 2
 | 
			
		||||
  #    end
 | 
			
		||||
  #
 | 
			
		||||
  #    t.enable(target: method(:m1))
 | 
			
		||||
  #
 | 
			
		||||
  #    m1
 | 
			
		||||
  #    # prints #<TracePoint:line@test.rb:5 in `m1'>
 | 
			
		||||
  #    m2
 | 
			
		||||
  #    # prints nothing
 | 
			
		||||
  #
 | 
			
		||||
  # Note: You cannot access event hooks within the +enable+ block.
 | 
			
		||||
  #
 | 
			
		||||
  #    trace.enable { p tp.lineno }
 | 
			
		||||
  #    #=> RuntimeError: access from outside
 | 
			
		||||
  #
 | 
			
		||||
  def enable(target: nil, target_line: nil, target_thread: nil)
 | 
			
		||||
    __builtin_tracepoint_enable_m(target, target_line, target_thread)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #	trace.disable		-> true or false
 | 
			
		||||
  #	trace.disable { block } -> obj
 | 
			
		||||
  #
 | 
			
		||||
  # Deactivates the trace
 | 
			
		||||
  #
 | 
			
		||||
  # Return true if trace was enabled.
 | 
			
		||||
  # Return false if trace was disabled.
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.enabled?	#=> true
 | 
			
		||||
  #	trace.disable	#=> true (previous status)
 | 
			
		||||
  #	trace.enabled?	#=> false
 | 
			
		||||
  #	trace.disable	#=> false
 | 
			
		||||
  #
 | 
			
		||||
  # If a block is given, the trace will only be disable within the scope of the
 | 
			
		||||
  # block.
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.enabled?
 | 
			
		||||
  #	#=> true
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.disable do
 | 
			
		||||
  #	    trace.enabled?
 | 
			
		||||
  #	    # only disabled for this block
 | 
			
		||||
  #	end
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.enabled?
 | 
			
		||||
  #	#=> true
 | 
			
		||||
  #
 | 
			
		||||
  # Note: You cannot access event hooks within the block.
 | 
			
		||||
  #
 | 
			
		||||
  #	trace.disable { p tp.lineno }
 | 
			
		||||
  #	#=> RuntimeError: access from outside
 | 
			
		||||
  def disable
 | 
			
		||||
    __builtin_tracepoint_disable_m
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # call-seq:
 | 
			
		||||
  #	trace.enabled?	    -> true or false
 | 
			
		||||
  #
 | 
			
		||||
  # The current status of the trace
 | 
			
		||||
  def enabled?
 | 
			
		||||
    __builtin_tracepoint_enabled_p
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Type of event
 | 
			
		||||
  #
 | 
			
		||||
  # See TracePoint@Events for more information.
 | 
			
		||||
  def event
 | 
			
		||||
    __builtin_tracepoint_attr_event
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Line number of the event
 | 
			
		||||
  def lineno
 | 
			
		||||
    __builtin_tracepoint_attr_lineno
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Path of the file being run
 | 
			
		||||
  def path
 | 
			
		||||
    __builtin_tracepoint_attr_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return the parameters definition of the method or block that the
 | 
			
		||||
  # current hook belongs to. Format is the same as for Method#parameters
 | 
			
		||||
  def parameters
 | 
			
		||||
    __builtin_tracepoint_attr_parameters
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return the name at the definition of the method being called
 | 
			
		||||
  def method_id
 | 
			
		||||
    __builtin_tracepoint_attr_method_id
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return the called name of the method being called
 | 
			
		||||
  def callee_id
 | 
			
		||||
    __builtin_tracepoint_attr_callee_id
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return class or module of the method being called.
 | 
			
		||||
  #
 | 
			
		||||
  #	class C; def foo; end; end
 | 
			
		||||
  # 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
  # 	  p tp.defined_class #=> C
 | 
			
		||||
  # 	end.enable do
 | 
			
		||||
  # 	  C.new.foo
 | 
			
		||||
  # 	end
 | 
			
		||||
  #
 | 
			
		||||
  # If method is defined by a module, then that module is returned.
 | 
			
		||||
  #
 | 
			
		||||
  #	module M; def foo; end; end
 | 
			
		||||
  # 	class C; include M; end;
 | 
			
		||||
  # 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
  # 	  p tp.defined_class #=> M
 | 
			
		||||
  # 	end.enable do
 | 
			
		||||
  # 	  C.new.foo
 | 
			
		||||
  # 	end
 | 
			
		||||
  #
 | 
			
		||||
  # <b>Note:</b> #defined_class returns singleton class.
 | 
			
		||||
  #
 | 
			
		||||
  # 6th block parameter of Kernel#set_trace_func passes original class
 | 
			
		||||
  # of attached by singleton class.
 | 
			
		||||
  #
 | 
			
		||||
  # <b>This is a difference between Kernel#set_trace_func and TracePoint.</b>
 | 
			
		||||
  #
 | 
			
		||||
  #	class C; def self.foo; end; end
 | 
			
		||||
  # 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
  # 	  p tp.defined_class #=> #<Class:C>
 | 
			
		||||
  # 	end.enable do
 | 
			
		||||
  # 	  C.foo
 | 
			
		||||
  # 	end
 | 
			
		||||
  def defined_class
 | 
			
		||||
    __builtin_tracepoint_attr_defined_class
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return the generated binding object from event
 | 
			
		||||
  def binding
 | 
			
		||||
    __builtin_tracepoint_attr_binding
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return the trace object during event
 | 
			
		||||
  #
 | 
			
		||||
  # Same as TracePoint#binding:
 | 
			
		||||
  #	trace.binding.eval('self')
 | 
			
		||||
  def self
 | 
			
		||||
    __builtin_tracepoint_attr_self
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  #  Return value from +:return+, +c_return+, and +b_return+ event
 | 
			
		||||
  def return_value
 | 
			
		||||
    __builtin_tracepoint_attr_return_value
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Value from exception raised on the +:raise+ event
 | 
			
		||||
  def raised_exception
 | 
			
		||||
    __builtin_tracepoint_attr_raised_exception
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Compiled source code (String) on *eval methods on the +:script_compiled+ event.
 | 
			
		||||
  # If loaded from a file, it will return nil.
 | 
			
		||||
  def eval_script
 | 
			
		||||
    __builtin_tracepoint_attr_eval_script
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Compiled instruction sequence represented by a RubyVM::InstructionSequence instance
 | 
			
		||||
  # on the +:script_compiled+ event.
 | 
			
		||||
  #
 | 
			
		||||
  # Note that this method is MRI specific.
 | 
			
		||||
  def instruction_sequence
 | 
			
		||||
    __builtin_tracepoint_attr_instruction_sequence
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										336
									
								
								vm_trace.c
									
										
									
									
									
								
							
							
						
						
									
										336
									
								
								vm_trace.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
#include "mjit.h"
 | 
			
		||||
#include "iseq.h"
 | 
			
		||||
#include "eval_intern.h"
 | 
			
		||||
#include "builtin.h"
 | 
			
		||||
 | 
			
		||||
/* (1) trace mechanisms */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1018,160 +1019,79 @@ rb_tracearg_object(rb_trace_arg_t *trace_arg)
 | 
			
		|||
    return trace_arg->data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Type of event
 | 
			
		||||
 *
 | 
			
		||||
 * See TracePoint@Events for more information.
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_event(VALUE tpval)
 | 
			
		||||
tracepoint_attr_event(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_event(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Line number of the event
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_lineno(VALUE tpval)
 | 
			
		||||
tracepoint_attr_lineno(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_lineno(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Path of the file being run
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_path(VALUE tpval)
 | 
			
		||||
tracepoint_attr_path(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_path(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the parameters definition of the method or block that the
 | 
			
		||||
 * current hook belongs to. Format is the same as for Method#parameters
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_parameters(VALUE tpval)
 | 
			
		||||
tracepoint_attr_parameters(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_parameters(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the name at the definition of the method being called
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_method_id(VALUE tpval)
 | 
			
		||||
tracepoint_attr_method_id(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_method_id(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the called name of the method being called
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_callee_id(VALUE tpval)
 | 
			
		||||
tracepoint_attr_callee_id(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_callee_id(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return class or module of the method being called.
 | 
			
		||||
 *
 | 
			
		||||
 *	class C; def foo; end; end
 | 
			
		||||
 * 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
 * 	  p tp.defined_class #=> C
 | 
			
		||||
 * 	end.enable do
 | 
			
		||||
 * 	  C.new.foo
 | 
			
		||||
 * 	end
 | 
			
		||||
 *
 | 
			
		||||
 * If method is defined by a module, then that module is returned.
 | 
			
		||||
 *
 | 
			
		||||
 *	module M; def foo; end; end
 | 
			
		||||
 * 	class C; include M; end;
 | 
			
		||||
 * 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
 * 	  p tp.defined_class #=> M
 | 
			
		||||
 * 	end.enable do
 | 
			
		||||
 * 	  C.new.foo
 | 
			
		||||
 * 	end
 | 
			
		||||
 *
 | 
			
		||||
 * <b>Note:</b> #defined_class returns singleton class.
 | 
			
		||||
 *
 | 
			
		||||
 * 6th block parameter of Kernel#set_trace_func passes original class
 | 
			
		||||
 * of attached by singleton class.
 | 
			
		||||
 *
 | 
			
		||||
 * <b>This is a difference between Kernel#set_trace_func and TracePoint.</b>
 | 
			
		||||
 *
 | 
			
		||||
 *	class C; def self.foo; end; end
 | 
			
		||||
 * 	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
 * 	  p tp.defined_class #=> #<Class:C>
 | 
			
		||||
 * 	end.enable do
 | 
			
		||||
 * 	  C.foo
 | 
			
		||||
 * 	end
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_defined_class(VALUE tpval)
 | 
			
		||||
tracepoint_attr_defined_class(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_defined_class(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the generated binding object from event
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_binding(VALUE tpval)
 | 
			
		||||
tracepoint_attr_binding(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_binding(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return the trace object during event
 | 
			
		||||
 *
 | 
			
		||||
 * Same as TracePoint#binding:
 | 
			
		||||
 *	trace.binding.eval('self')
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_self(VALUE tpval)
 | 
			
		||||
tracepoint_attr_self(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_self(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Return value from +:return+, +c_return+, and +b_return+ event
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_return_value(VALUE tpval)
 | 
			
		||||
tracepoint_attr_return_value(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_return_value(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Value from exception raised on the +:raise+ event
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_raised_exception(VALUE tpval)
 | 
			
		||||
tracepoint_attr_raised_exception(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_raised_exception(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Compiled source code (String) on *eval methods on the +:script_compiled+ event.
 | 
			
		||||
 * If loaded from a file, it will return nil.
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_eval_script(VALUE tpval)
 | 
			
		||||
tracepoint_attr_eval_script(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_eval_script(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Compiled instruction sequence represented by a RubyVM::InstructionSequence instance
 | 
			
		||||
 * on the +:script_compiled+ event.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that this method is MRI specific.
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_attr_instruction_sequence(VALUE tpval)
 | 
			
		||||
tracepoint_attr_instruction_sequence(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracearg_instruction_sequence(get_trace_arg());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1352,11 +1272,8 @@ rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
 | 
			
		|||
    list->events = events;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* :nodoc:
 | 
			
		||||
 * Docs for the TracePointe#enable are in prelude.rb
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_enable_m(VALUE tpval, VALUE target, VALUE target_line, VALUE target_thread)
 | 
			
		||||
tracepoint_enable_m(rb_execution_context_t *ec, VALUE tpval, VALUE target, VALUE target_line, VALUE target_thread)
 | 
			
		||||
{
 | 
			
		||||
    rb_tp_t *tp = tpptr(tpval);
 | 
			
		||||
    int previous_tracing = tp->tracing;
 | 
			
		||||
| 
						 | 
				
			
			@ -1392,43 +1309,8 @@ tracepoint_enable_m(VALUE tpval, VALUE target, VALUE target_line, VALUE target_t
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * call-seq:
 | 
			
		||||
 *	trace.disable		-> true or false
 | 
			
		||||
 *	trace.disable { block } -> obj
 | 
			
		||||
 *
 | 
			
		||||
 * Deactivates the trace
 | 
			
		||||
 *
 | 
			
		||||
 * Return true if trace was enabled.
 | 
			
		||||
 * Return false if trace was disabled.
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.enabled?	#=> true
 | 
			
		||||
 *	trace.disable	#=> true (previous status)
 | 
			
		||||
 *	trace.enabled?	#=> false
 | 
			
		||||
 *	trace.disable	#=> false
 | 
			
		||||
 *
 | 
			
		||||
 * If a block is given, the trace will only be disable within the scope of the
 | 
			
		||||
 * block.
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.enabled?
 | 
			
		||||
 *	#=> true
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.disable do
 | 
			
		||||
 *	    trace.enabled?
 | 
			
		||||
 *	    # only disabled for this block
 | 
			
		||||
 *	end
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.enabled?
 | 
			
		||||
 *	#=> true
 | 
			
		||||
 *
 | 
			
		||||
 * Note: You cannot access event hooks within the block.
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.disable { p tp.lineno }
 | 
			
		||||
 *	#=> RuntimeError: access from outside
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_disable_m(VALUE tpval)
 | 
			
		||||
tracepoint_disable_m(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    rb_tp_t *tp = tpptr(tpval);
 | 
			
		||||
    int previous_tracing = tp->tracing;
 | 
			
		||||
| 
						 | 
				
			
			@ -1449,12 +1331,6 @@ tracepoint_disable_m(VALUE tpval)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * call-seq:
 | 
			
		||||
 *	trace.enabled?	    -> true or false
 | 
			
		||||
 *
 | 
			
		||||
 * The current status of the trace
 | 
			
		||||
 */
 | 
			
		||||
VALUE
 | 
			
		||||
rb_tracepoint_enabled_p(VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1462,6 +1338,12 @@ rb_tracepoint_enabled_p(VALUE tpval)
 | 
			
		|||
    return tp->tracing ? Qtrue : Qfalse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_enabled_p(rb_execution_context_t *ec, VALUE tpval)
 | 
			
		||||
{
 | 
			
		||||
    return rb_tracepoint_enabled_p(tpval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_new(VALUE klass, rb_thread_t *target_th, rb_event_flag_t events, void (func)(VALUE, void*), void *data, VALUE proc)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1522,63 +1404,17 @@ rb_tracepoint_new(VALUE target_thval, rb_event_flag_t events, void (*func)(VALUE
 | 
			
		|||
    return tracepoint_new(rb_cTracePoint, target_th, events, func, data, Qundef);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * call-seq:
 | 
			
		||||
 *	TracePoint.new(*events) { |obj| block }	    -> obj
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a new TracePoint object, not enabled by default.
 | 
			
		||||
 *
 | 
			
		||||
 * Next, in order to activate the trace, you must use TracePoint#enable
 | 
			
		||||
 *
 | 
			
		||||
 *	trace = TracePoint.new(:call) do |tp|
 | 
			
		||||
 *	    p [tp.lineno, tp.defined_class, tp.method_id, tp.event]
 | 
			
		||||
 *	end
 | 
			
		||||
 *	#=> #<TracePoint:disabled>
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.enable
 | 
			
		||||
 *	#=> false
 | 
			
		||||
 *
 | 
			
		||||
 *	puts "Hello, TracePoint!"
 | 
			
		||||
 *	# ...
 | 
			
		||||
 *	# [48, IRB::Notifier::AbstractNotifier, :printf, :call]
 | 
			
		||||
 *	# ...
 | 
			
		||||
 *
 | 
			
		||||
 * When you want to deactivate the trace, you must use TracePoint#disable
 | 
			
		||||
 *
 | 
			
		||||
 *	trace.disable
 | 
			
		||||
 *
 | 
			
		||||
 * See TracePoint@Events for possible events and more information.
 | 
			
		||||
 *
 | 
			
		||||
 * A block must be given, otherwise an ArgumentError is raised.
 | 
			
		||||
 *
 | 
			
		||||
 * If the trace method isn't included in the given events filter, a
 | 
			
		||||
 * RuntimeError is raised.
 | 
			
		||||
 *
 | 
			
		||||
 *	TracePoint.trace(:line) do |tp|
 | 
			
		||||
 *	    p tp.raised_exception
 | 
			
		||||
 *	end
 | 
			
		||||
 *	#=> RuntimeError: 'raised_exception' not supported by this event
 | 
			
		||||
 *
 | 
			
		||||
 * If the trace method is called outside block, a RuntimeError is raised.
 | 
			
		||||
 *
 | 
			
		||||
 *      TracePoint.trace(:line) do |tp|
 | 
			
		||||
 *        $tp = tp
 | 
			
		||||
 *      end
 | 
			
		||||
 *      $tp.lineno #=> access from outside (RuntimeError)
 | 
			
		||||
 *
 | 
			
		||||
 * Access from other threads is also forbidden.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_new_s(int argc, VALUE *argv, VALUE self)
 | 
			
		||||
tracepoint_new_s(rb_execution_context_t *ec, VALUE self, VALUE args)
 | 
			
		||||
{
 | 
			
		||||
    rb_event_flag_t events = 0;
 | 
			
		||||
    int i;
 | 
			
		||||
    long i;
 | 
			
		||||
    long argc = RARRAY_LEN(args);
 | 
			
		||||
 | 
			
		||||
    if (argc > 0) {
 | 
			
		||||
	for (i=0; i<argc; i++) {
 | 
			
		||||
	    events |= symbol2event_flag(argv[i]);
 | 
			
		||||
	}
 | 
			
		||||
        for (i=0; i<argc; i++) {
 | 
			
		||||
	    events |= symbol2event_flag(RARRAY_AREF(args, i));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
	events = RUBY_EVENT_TRACEPOINT_ALL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1592,23 +1428,15 @@ tracepoint_new_s(int argc, VALUE *argv, VALUE self)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_trace_s(int argc, VALUE *argv, VALUE self)
 | 
			
		||||
tracepoint_trace_s(rb_execution_context_t *ec, VALUE self, VALUE args)
 | 
			
		||||
{
 | 
			
		||||
    VALUE trace = tracepoint_new_s(argc, argv, self);
 | 
			
		||||
    VALUE trace = tracepoint_new_s(ec, self, args);
 | 
			
		||||
    rb_tracepoint_enable(trace);
 | 
			
		||||
    return trace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *    trace.inspect  -> string
 | 
			
		||||
 *
 | 
			
		||||
 *  Return a string containing a human-readable TracePoint
 | 
			
		||||
 *  status.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_inspect(VALUE self)
 | 
			
		||||
tracepoint_inspect(rb_execution_context_t *ec, VALUE self)
 | 
			
		||||
{
 | 
			
		||||
    rb_tp_t *tp = tpptr(self);
 | 
			
		||||
    rb_trace_arg_t *trace_arg = GET_EC()->trace_arg;
 | 
			
		||||
| 
						 | 
				
			
			@ -1671,20 +1499,8 @@ tracepoint_stat_event_hooks(VALUE hash, VALUE key, rb_event_hook_t *hook)
 | 
			
		|||
    rb_hash_aset(hash, key, rb_ary_new3(2, INT2FIX(active), INT2FIX(deleted)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * call-seq:
 | 
			
		||||
 *	TracePoint.stat -> obj
 | 
			
		||||
 *
 | 
			
		||||
 *  Returns internal information of TracePoint.
 | 
			
		||||
 *
 | 
			
		||||
 *  The contents of the returned value are implementation specific.
 | 
			
		||||
 *  It may be changed in future.
 | 
			
		||||
 *
 | 
			
		||||
 *  This method is only for debugging TracePoint itself.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
tracepoint_stat_s(VALUE self)
 | 
			
		||||
tracepoint_stat_s(rb_execution_context_t *ec, VALUE self)
 | 
			
		||||
{
 | 
			
		||||
    rb_vm_t *vm = GET_VM();
 | 
			
		||||
    VALUE stat = rb_hash_new();
 | 
			
		||||
| 
						 | 
				
			
			@ -1695,6 +1511,8 @@ tracepoint_stat_s(VALUE self)
 | 
			
		|||
    return stat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "load_trace_point.inc"
 | 
			
		||||
 | 
			
		||||
/* This function is called from inits.c */
 | 
			
		||||
void
 | 
			
		||||
Init_vm_trace(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -1704,94 +1522,10 @@ Init_vm_trace(void)
 | 
			
		|||
    rb_define_method(rb_cThread, "set_trace_func", thread_set_trace_func_m, 1);
 | 
			
		||||
    rb_define_method(rb_cThread, "add_trace_func", thread_add_trace_func_m, 1);
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Document-class: TracePoint
 | 
			
		||||
     *
 | 
			
		||||
     * A class that provides the functionality of Kernel#set_trace_func in a
 | 
			
		||||
     * nice Object-Oriented API.
 | 
			
		||||
     *
 | 
			
		||||
     * == Example
 | 
			
		||||
     *
 | 
			
		||||
     * We can use TracePoint to gather information specifically for exceptions:
 | 
			
		||||
     *
 | 
			
		||||
     *	    trace = TracePoint.new(:raise) do |tp|
 | 
			
		||||
     *		p [tp.lineno, tp.event, tp.raised_exception]
 | 
			
		||||
     *	    end
 | 
			
		||||
     *	    #=> #<TracePoint:disabled>
 | 
			
		||||
     *
 | 
			
		||||
     *	    trace.enable
 | 
			
		||||
     *	    #=> false
 | 
			
		||||
     *
 | 
			
		||||
     *	    0 / 0
 | 
			
		||||
     *	    #=> [5, :raise, #<ZeroDivisionError: divided by 0>]
 | 
			
		||||
     *
 | 
			
		||||
     * == Events
 | 
			
		||||
     *
 | 
			
		||||
     * If you don't specify the type of events you want to listen for,
 | 
			
		||||
     * TracePoint will include all available events.
 | 
			
		||||
     *
 | 
			
		||||
     * *Note* do not depend on current event set, as this list is subject to
 | 
			
		||||
     * change. Instead, it is recommended you specify the type of events you
 | 
			
		||||
     * want to use.
 | 
			
		||||
     *
 | 
			
		||||
     * To filter what is traced, you can pass any of the following as +events+:
 | 
			
		||||
     *
 | 
			
		||||
     * +:line+:: execute code on a new line
 | 
			
		||||
     * +:class+:: start a class or module definition
 | 
			
		||||
     * +:end+:: finish a class or module definition
 | 
			
		||||
     * +:call+:: call a Ruby method
 | 
			
		||||
     * +:return+:: return from a Ruby method
 | 
			
		||||
     * +:c_call+:: call a C-language routine
 | 
			
		||||
     * +:c_return+:: return from a C-language routine
 | 
			
		||||
     * +:raise+:: raise an exception
 | 
			
		||||
     * +:b_call+:: event hook at block entry
 | 
			
		||||
     * +:b_return+:: event hook at block ending
 | 
			
		||||
     * +:thread_begin+:: event hook at thread beginning
 | 
			
		||||
     * +:thread_end+:: event hook at thread ending
 | 
			
		||||
     * +:fiber_switch+:: event hook at fiber switch
 | 
			
		||||
     * +:script_compiled+:: new Ruby code compiled (with +eval+, +load+ or +require+)
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    rb_cTracePoint = rb_define_class("TracePoint", rb_cObject);
 | 
			
		||||
    rb_undef_alloc_func(rb_cTracePoint);
 | 
			
		||||
    rb_define_singleton_method(rb_cTracePoint, "new", tracepoint_new_s, -1);
 | 
			
		||||
    /*
 | 
			
		||||
     * Document-method: trace
 | 
			
		||||
     *
 | 
			
		||||
     * call-seq:
 | 
			
		||||
     *	TracePoint.trace(*events) { |obj| block }	-> obj
 | 
			
		||||
     *
 | 
			
		||||
     *  A convenience method for TracePoint.new, that activates the trace
 | 
			
		||||
     *  automatically.
 | 
			
		||||
     *
 | 
			
		||||
     *	    trace = TracePoint.trace(:call) { |tp| [tp.lineno, tp.event] }
 | 
			
		||||
     *	    #=> #<TracePoint:enabled>
 | 
			
		||||
     *
 | 
			
		||||
     *	    trace.enabled? #=> true
 | 
			
		||||
     */
 | 
			
		||||
    rb_define_singleton_method(rb_cTracePoint, "trace", tracepoint_trace_s, -1);
 | 
			
		||||
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "__enable", tracepoint_enable_m, 3);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "disable", tracepoint_disable_m, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "enabled?", rb_tracepoint_enabled_p, 0);
 | 
			
		||||
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "inspect", tracepoint_inspect, 0);
 | 
			
		||||
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "event", tracepoint_attr_event, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "lineno", tracepoint_attr_lineno, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "path", tracepoint_attr_path, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "parameters", tracepoint_attr_parameters, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "method_id", tracepoint_attr_method_id, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "callee_id", tracepoint_attr_callee_id, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "defined_class", tracepoint_attr_defined_class, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "binding", tracepoint_attr_binding, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "self", tracepoint_attr_self, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "return_value", tracepoint_attr_return_value, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "raised_exception", tracepoint_attr_raised_exception, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "eval_script", tracepoint_attr_eval_script, 0);
 | 
			
		||||
    rb_define_method(rb_cTracePoint, "instruction_sequence", tracepoint_attr_instruction_sequence, 0);
 | 
			
		||||
 | 
			
		||||
    rb_define_singleton_method(rb_cTracePoint, "stat", tracepoint_stat_s, 0);
 | 
			
		||||
    load_trace_point();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct rb_postponed_job_struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue