summaryrefslogtreecommitdiff
path: root/vm_core.h
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-26 18:16:39 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-26 18:16:39 +0000
commit96990203b71184003cf8a9bad5cc177645820fd4 (patch)
tree002653edece27aa30772c373cc6a83c0de928cc8 /vm_core.h
parent2c9259e6e01726234360a2e432ffc882b52ff793 (diff)
Support targetting TracePoint [Feature #15289]
* vm_trace.c (rb_tracepoint_enable_for_target): support targetting TracePoint. [Feature #15289] Tragetting TracePoint is only enabled on specified method, proc and so on, example: `tp.enable(target: code)`. `code` should be consisted of InstructionSeuqnece (iseq) (RubyVM::InstructionSeuqnece.of(code) should not return nil) If code is a tree of iseq, TracePoint is enabled on all of iseqs in a tree. Enabled tragetting TracePoints can not enabled again with and without target. * vm_core.h (rb_iseq_t): introduce `rb_iseq_t::local_hooks` to store local hooks. `rb_iseq_t::aux::trace_events` is renamed to `global_trace_events` to contrast with `local_hooks`. * vm_core.h (rb_hook_list_t): add `rb_hook_list_t::running` to represent how many Threads/Fibers are used this list. If this field is 0, nobody using this hooks and we can delete it. This is why we can remove code from cont.c. * vm_core.h (rb_vm_t): because of above change, we can eliminate `rb_vm_t::trace_running` field. Also renamed from `rb_vm_t::event_hooks` to `global_hooks`. * vm_core.h, vm.c (ruby_vm_event_enabled_global_flags): renamed from `ruby_vm_event_enabled_flags. * vm_core.h, vm.c (ruby_vm_event_local_num): added to count enabled targetting TracePoints. * vm_core.h, vm_trace.c (rb_exec_event_hooks): accepts hook list. * vm_core.h (rb_vm_global_hooks): added for convinience. * method.h (rb_method_bmethod_t): added to maintain Proc and `rb_hook_list_t` for bmethod (defined by define_method). * prelude.rb (TracePoint#enable): extracet a keyword parameter (because it is easy than writing in C). It calls `TracePoint#__enable` internal method written in C. * vm_insnhelper.c (vm_trace): check also iseq->local_hooks. * vm.c (invoke_bmethod): check def->body.bmethod.hooks. * vm.c (hook_before_rewind): check iseq->local_hooks and def->body.bmethod.hooks before rewind by exception. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66003 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_core.h')
-rw-r--r--vm_core.h51
1 files changed, 32 insertions, 19 deletions
diff --git a/vm_core.h b/vm_core.h
index d578b5c..b22a1fb 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -474,7 +474,7 @@ struct rb_iseq_constant_body {
/* typedef rb_iseq_t is in method.h */
struct rb_iseq_struct {
VALUE flags;
- VALUE reserved1;
+ struct rb_hook_list_struct *local_hooks;
struct rb_iseq_constant_body *body;
union { /* 4, 5 words */
@@ -485,7 +485,7 @@ struct rb_iseq_struct {
int index;
} loader;
- rb_event_flag_t trace_events;
+ rb_event_flag_t global_trace_events;
} aux;
};
@@ -577,7 +577,8 @@ void rb_objspace_free(struct rb_objspace *);
typedef struct rb_hook_list_struct {
struct rb_event_hook_struct *hooks;
rb_event_flag_t events;
- int need_clean;
+ unsigned int need_clean;
+ unsigned int running;
} rb_hook_list_t;
typedef struct rb_vm_struct {
@@ -608,8 +609,6 @@ typedef struct rb_vm_struct {
unsigned int thread_report_on_exception: 1;
unsigned int safe_level_: 1;
-
- int trace_running;
int sleeper;
/* object management */
@@ -634,7 +633,7 @@ typedef struct rb_vm_struct {
} trap_list;
/* hook */
- rb_hook_list_t event_hooks;
+ rb_hook_list_t global_hooks;
/* relation table of ensure - rollback for callcc */
struct st_table *ensure_rollback_table;
@@ -1694,7 +1693,8 @@ RUBY_SYMBOL_EXPORT_BEGIN
RUBY_EXTERN rb_vm_t *ruby_current_vm_ptr;
RUBY_EXTERN rb_execution_context_t *ruby_current_execution_context_ptr;
RUBY_EXTERN rb_event_flag_t ruby_vm_event_flags;
-RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_flags;
+RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags;
+RUBY_EXTERN unsigned int ruby_vm_event_local_num;
RUBY_SYMBOL_EXPORT_END
@@ -1805,6 +1805,7 @@ rb_vm_check_ints(rb_execution_context_t *ec)
}
/* tracer */
+
struct rb_trace_arg_struct {
rb_event_flag_t event;
rb_execution_context_t *ec;
@@ -1822,24 +1823,29 @@ struct rb_trace_arg_struct {
VALUE path;
};
-void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, int pop_p);
+void rb_hook_list_mark(rb_hook_list_t *hooks);
+void rb_hook_list_free(rb_hook_list_t *hooks);
+void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval);
+void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval);
-#define EXEC_EVENT_HOOK_ORIG(ec_, flag_, vm_flags_, self_, id_, called_id_, klass_, data_, pop_p_) do { \
+void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p);
+
+#define EXEC_EVENT_HOOK_ORIG(ec_, hooks_, flag_, self_, id_, called_id_, klass_, data_, pop_p_) do { \
const rb_event_flag_t flag_arg_ = (flag_); \
- if (UNLIKELY(vm_flags_ & (flag_arg_))) { \
- /* defer evaluating the other arguments */ \
- rb_exec_event_hook_orig(ec_, flag_arg_, self_, id_, called_id_, klass_, data_, pop_p_); \
+ rb_hook_list_t *hooks_arg_ = (hooks_); \
+ if (UNLIKELY((hooks_arg_)->events & (flag_arg_))) { \
+ /* defer evaluating the other arguments */ \
+ rb_exec_event_hook_orig(ec_, hooks_arg_, flag_arg_, self_, id_, called_id_, klass_, data_, pop_p_); \
} \
} while (0)
static inline void
-rb_exec_event_hook_orig(rb_execution_context_t *ec, const rb_event_flag_t flag,
- VALUE self, ID id, ID called_id, VALUE klass, VALUE data, int pop_p)
+rb_exec_event_hook_orig(rb_execution_context_t *ec, rb_hook_list_t *hooks, rb_event_flag_t flag,
+ VALUE self, ID id, ID called_id, VALUE klass, VALUE data, int pop_p)
{
struct rb_trace_arg_struct trace_arg;
- VM_ASSERT(rb_ec_vm_ptr(ec)->event_hooks.events == ruby_vm_event_flags);
- VM_ASSERT(rb_ec_vm_ptr(ec)->event_hooks.events & flag);
+ VM_ASSERT((hooks->events & flag) != 0);
trace_arg.event = flag;
trace_arg.ec = ec;
@@ -1851,14 +1857,21 @@ rb_exec_event_hook_orig(rb_execution_context_t *ec, const rb_event_flag_t flag,
trace_arg.data = data;
trace_arg.path = Qundef;
trace_arg.klass_solved = 0;
- rb_exec_event_hooks(&trace_arg, pop_p);
+
+ rb_exec_event_hooks(&trace_arg, hooks, pop_p);
+}
+
+static inline rb_hook_list_t *
+rb_vm_global_hooks(const rb_execution_context_t *ec)
+{
+ return &rb_ec_vm_ptr(ec)->global_hooks;
}
#define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_) \
- EXEC_EVENT_HOOK_ORIG(ec_, flag_, ruby_vm_event_flags, self_, id_, called_id_, klass_, data_, 0)
+ EXEC_EVENT_HOOK_ORIG(ec_, rb_vm_global_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 0)
#define EXEC_EVENT_HOOK_AND_POP_FRAME(ec_, flag_, self_, id_, called_id_, klass_, data_) \
- EXEC_EVENT_HOOK_ORIG(ec_, flag_, ruby_vm_event_flags, self_, id_, called_id_, klass_, data_, 1)
+ EXEC_EVENT_HOOK_ORIG(ec_, rb_vm_global_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 1)
RUBY_SYMBOL_EXPORT_BEGIN