rb-threadframe 0.32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ /* Ruby 1.9 externs that we need.
2
+
3
+ We assume all structure typedefs needed below have been defined
4
+ previously.
5
+
6
+ Routines marked "new" are not found in an unmodified Ruby 1.9.
7
+ Routines marked remove "static" are static routines that need to be
8
+ made extern.
9
+ */
10
+
11
+
12
+ /* From iseq */
13
+ extern VALUE iseq_alloc_shared(VALUE klass); /* new */
14
+ extern VALUE rb_cISeq;
15
+ extern const char * ruby_node_name(int node);
16
+ extern VALUE rb_iseq_arity(VALUE iseqval);
17
+
18
+ /* From proc.c */
19
+ extern int method_arity(VALUE method); /* removed "static" */
20
+ extern VALUE rb_binding_frame_new(void *vth, void *vcfp); /* new */
21
+
22
+
23
+ /* From thread.c */
24
+ extern rb_control_frame_t * thread_control_frame(void *); /* new */
25
+ extern VALUE rb_cThread; /* Thread class */
26
+
27
+
28
+ extern VALUE rb_iseq_disasm_internal(rb_iseq_t *iseqdat); /* new */
29
+ extern VALUE rb_cRubyVM; /* RubyVM class */
30
+
31
+ /* From vm.c */
32
+ extern int rb_vm_get_sourceline(const rb_control_frame_t *cfp);
33
+ extern rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(rb_thread_t *th, rb_control_frame_t *cfp);
34
+
35
+ /* From node.c */
36
+ extern VALUE rb_parser_dump_tree(NODE *node, int comment);
@@ -0,0 +1,24 @@
1
+ /**********************************************************************
2
+
3
+ thread_pthread.h -
4
+
5
+ $Author$
6
+
7
+ Copyright (C) 2004-2007 Koichi Sasada
8
+
9
+ **********************************************************************/
10
+
11
+ #ifndef RUBY_THREAD_PTHREAD_H
12
+ #define RUBY_THREAD_PTHREAD_H
13
+
14
+ #include <pthread.h>
15
+ typedef pthread_t rb_thread_id_t;
16
+ typedef pthread_mutex_t rb_thread_lock_t;
17
+ typedef pthread_cond_t rb_thread_cond_t;
18
+
19
+ typedef struct native_thread_data_struct {
20
+ void *signal_thread_list;
21
+ pthread_cond_t sleep_cond;
22
+ } native_thread_data_t;
23
+
24
+ #endif /* RUBY_THREAD_PTHREAD_H */
@@ -0,0 +1,357 @@
1
+ /* Headers Exposing a little more of the 1.9 runtime and some
2
+ method prototypes for extensions to the Thread class.
3
+ */
4
+ #include <ruby.h>
5
+ #include <signal.h>
6
+ #include "thread_pthread.h"
7
+ #include "node.h"
8
+
9
+ /* From vm_core.h: */
10
+
11
+ /* Frame information: */
12
+ #define VM_FRAME_MAGIC_METHOD 0x11
13
+ #define VM_FRAME_MAGIC_BLOCK 0x21
14
+ #define VM_FRAME_MAGIC_CLASS 0x31
15
+ #define VM_FRAME_MAGIC_TOP 0x41
16
+ #define VM_FRAME_MAGIC_FINISH 0x51
17
+ #define VM_FRAME_MAGIC_CFUNC 0x61
18
+ #define VM_FRAME_MAGIC_PROC 0x71
19
+ #define VM_FRAME_MAGIC_IFUNC 0x81
20
+ #define VM_FRAME_MAGIC_EVAL 0x91
21
+ #define VM_FRAME_MAGIC_LAMBDA 0xa1
22
+ #define VM_FRAME_MAGIC_MASK_BITS 8
23
+ #define VM_FRAME_MAGIC_MASK (~(~0<<VM_FRAME_MAGIC_MASK_BITS))
24
+
25
+ #define VM_FRAME_TYPE(cfp) ((cfp)->flag & VM_FRAME_MAGIC_MASK)
26
+
27
+ #define VM_FRAME_TRACE_RETURN 0x01 /* Call trace hook on return. */
28
+ #define VM_FRAME_TRACE_OFF 0x02 /* Turn of event hook tracing in this frame
29
+ and any frames created from this one. */
30
+
31
+ /* other frame flag */
32
+ #define VM_FRAME_FLAG_PASSED 0x0100
33
+
34
+ #define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp) (cfp+1)
35
+ #define RUBYVM_CFUNC_FRAME_P(cfp) \
36
+ (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC)
37
+ #define RUBY_VM_NEXT_CONTROL_FRAME(cfp) (cfp-1)
38
+ #define RUBY_VM_END_CONTROL_FRAME(th) \
39
+ ((rb_control_frame_t *)((th)->stack + (th)->stack_size))
40
+ #define RUBY_VM_VALID_CONTROL_FRAME_P(cfp, ecfp) \
41
+ ((void *)(ecfp) > (void *)(cfp))
42
+ #define RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp) \
43
+ (!RUBY_VM_VALID_CONTROL_FRAME_P((cfp), RUBY_VM_END_CONTROL_FRAME(th)))
44
+
45
+ #define RUBY_VM_IFUNC_P(ptr) (BUILTIN_TYPE(ptr) == T_NODE)
46
+ #define RUBY_VM_NORMAL_ISEQ_P(ptr) \
47
+ (ptr && !RUBY_VM_IFUNC_P(ptr))
48
+
49
+
50
+ #if 1
51
+ #define GetCoreDataFromValue(obj, type, ptr) do { \
52
+ ptr = (type*)DATA_PTR(obj); \
53
+ } while (0)
54
+ #else
55
+ #define GetCoreDataFromValue(obj, type, ptr) Data_Get_Struct(obj, type, ptr)
56
+ #endif
57
+ #if 1
58
+ #define GetCoreDataFromValue(obj, type, ptr) do { \
59
+ ptr = (type*)DATA_PTR(obj); \
60
+ } while (0)
61
+ #else
62
+ #define GetCoreDataFromValue(obj, type, ptr) Data_Get_Struct(obj, type, ptr)
63
+ #endif
64
+ #define GetISeqPtr(obj, ptr) \
65
+ GetCoreDataFromValue(obj, rb_iseq_t, ptr)
66
+
67
+ /* Opaque types (for now at least) */
68
+ typedef struct iseq_catch_table_entry iseq_catch_table_entry_t;
69
+
70
+ #ifndef NSIG
71
+ # define NSIG (_SIGMAX + 1) /* For QNX */
72
+ #endif
73
+
74
+ #define RUBY_NSIG NSIG
75
+
76
+ typedef struct rb_compile_option_struct {
77
+ int inline_const_cache;
78
+ int peephole_optimization;
79
+ int tailcall_optimization;
80
+ int specialized_instruction;
81
+ int operands_unification;
82
+ int instructions_unification;
83
+ int stack_caching;
84
+ int trace_instruction;
85
+ int debug_level;
86
+ } rb_compile_option_t;
87
+
88
+ /* Instruction sequence */
89
+ typedef struct rb_iseq_struct {
90
+ /***************/
91
+ /* static data */
92
+ /***************/
93
+
94
+ VALUE type; /* instruction sequence type */
95
+ VALUE name; /* String: iseq name */
96
+ VALUE filename; /* file information where this sequence from */
97
+ VALUE filepath; /* real file path or nil */
98
+ VALUE *iseq; /* iseq (insn number and operands) */
99
+ VALUE *iseq_encoded; /* encoded iseq */
100
+ unsigned long iseq_size;
101
+ VALUE mark_ary; /* Array: includes operands which should be GC marked */
102
+ VALUE coverage; /* coverage array */
103
+ unsigned short line_no;
104
+
105
+ /* insn info, must be freed */
106
+ struct iseq_insn_info_entry *insn_info_table;
107
+ size_t insn_info_size;
108
+
109
+ ID *local_table; /* must free */
110
+ int local_table_size;
111
+
112
+ /* method, class frame: sizeof(vars) + 1, block frame: sizeof(vars) */
113
+ int local_size;
114
+
115
+ struct iseq_inline_cache_entry *ic_entries;
116
+ int ic_size;
117
+
118
+ /**
119
+ * argument information
120
+ *
121
+ * def m(a1, a2, ..., aM, # mandatory
122
+ * b1=(...), b2=(...), ..., bN=(...), # optional
123
+ * *c, # rest
124
+ * d1, d2, ..., dO, # post
125
+ * &e) # block
126
+ * =>
127
+ *
128
+ * argc = M
129
+ * arg_rest = M+N+1 // or -1 if no rest arg
130
+ * arg_opts = N
131
+ * arg_opts_tbl = [ (N entries) ]
132
+ * arg_post_len = O // 0 if no post arguments
133
+ * arg_post_start = M+N+2
134
+ * arg_block = M+N + 1 + O + 1 // -1 if no block arg
135
+ * arg_simple = 0 if not simple arguments.
136
+ * = 1 if no opt, rest, post, block.
137
+ * = 2 if ambiguos block parameter ({|a|}).
138
+ * arg_size = argument size.
139
+ */
140
+
141
+ int argc;
142
+ int arg_simple;
143
+ int arg_rest;
144
+ int arg_block;
145
+ int arg_opts;
146
+ int arg_post_len;
147
+ int arg_post_start;
148
+ int arg_size;
149
+ VALUE *arg_opt_table;
150
+
151
+ size_t stack_max; /* for stack overflow check */
152
+
153
+ /* catch table */
154
+ iseq_catch_table_entry_t *catch_table;
155
+ int catch_table_size;
156
+
157
+ /* for child iseq */
158
+ struct rb_iseq_struct *parent_iseq;
159
+ struct rb_iseq_struct *local_iseq;
160
+
161
+ /****************/
162
+ /* dynamic data */
163
+ /****************/
164
+
165
+ VALUE self;
166
+ VALUE orig; /* non-NULL if its data have origin */
167
+
168
+ /* block inlining */
169
+ /*
170
+ * NODE *node;
171
+ * void *special_block_builder;
172
+ * void *cached_special_block_builder;
173
+ * VALUE cached_special_block;
174
+ */
175
+
176
+ /* klass/module nest information stack (cref) */
177
+ NODE *cref_stack;
178
+ VALUE klass;
179
+
180
+ /* misc */
181
+ ID defined_method_id; /* for define_method */
182
+
183
+ /* used at compile time */
184
+ struct iseq_compile_data *compile_data;
185
+ /* Used to set a breakpoint at a VM instruction */
186
+ unsigned char *breakpoints;
187
+ } rb_iseq_t;
188
+
189
+ enum ruby_special_exceptions {
190
+ ruby_error_reenter,
191
+ ruby_error_nomemory,
192
+ ruby_error_sysstack,
193
+ ruby_special_error_count
194
+ };
195
+
196
+ typedef struct rb_vm_struct {
197
+ VALUE self;
198
+
199
+ rb_thread_lock_t global_vm_lock;
200
+
201
+ struct rb_thread_struct *main_thread;
202
+ struct rb_thread_struct *running_thread;
203
+
204
+ st_table *living_threads;
205
+ VALUE thgroup_default;
206
+
207
+ int running;
208
+ int thread_abort_on_exception;
209
+ unsigned long trace_flag;
210
+ volatile int sleeper;
211
+
212
+ /* object management */
213
+ VALUE mark_object_ary;
214
+
215
+ VALUE special_exceptions[ruby_special_error_count];
216
+
217
+ /* load */
218
+ VALUE top_self;
219
+ VALUE load_path;
220
+ VALUE loaded_features;
221
+ struct st_table *loading_table;
222
+
223
+ /* signal */
224
+ struct {
225
+ VALUE cmd;
226
+ int safe;
227
+ } trap_list[RUBY_NSIG];
228
+
229
+ /* hook */
230
+ rb_event_hook_t *event_hooks;
231
+
232
+ int src_encoding_index;
233
+
234
+ VALUE verbose, debug, progname;
235
+ VALUE coverages;
236
+
237
+ struct unlinked_method_entry_list_entry *unlinked_method_entry_list;
238
+
239
+ #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
240
+ struct rb_objspace *objspace;
241
+ #endif
242
+ } rb_vm_t;
243
+
244
+ #include "method_mini.h"
245
+
246
+ typedef struct {
247
+ VALUE *pc; /* cfp[0] */
248
+ VALUE *sp; /* cfp[1] */
249
+ VALUE *bp; /* cfp[2] */
250
+ rb_iseq_t *iseq; /* cfp[3] */
251
+ VALUE flag; /* cfp[4] */
252
+ VALUE self; /* cfp[5] / block[0] */
253
+ VALUE *lfp; /* cfp[6] / block[1] */
254
+ VALUE *dfp; /* cfp[7] / block[2] */
255
+ rb_iseq_t *block_iseq; /* cfp[8] / block[3] */
256
+ VALUE proc; /* cfp[9] / block[4] */
257
+ const rb_method_entry_t *me;/* cfp[10] */
258
+ short int tracing; /* Bits to control per-frame event tracing.
259
+ See VM_FRAME_TRACE_xxx defines.
260
+ */
261
+ } rb_control_frame_t;
262
+
263
+ typedef struct rb_block_struct {
264
+ VALUE self; /* share with method frame if it's only block */
265
+ VALUE *lfp; /* share with method frame if it's only block */
266
+ VALUE *dfp; /* share with method frame if it's only block */
267
+ rb_iseq_t *iseq;
268
+ VALUE proc;
269
+ } rb_block_t;
270
+
271
+ #define GetThreadPtr(obj, ptr) \
272
+ GetCoreDataFromValue(obj, rb_thread_t, ptr)
273
+
274
+ #define GetProcPtr(obj, ptr) \
275
+ GetCoreDataFromValue(obj, rb_proc_t, ptr)
276
+
277
+ typedef struct rb_thread_struct
278
+ {
279
+ VALUE self;
280
+ rb_vm_t *vm;
281
+
282
+ /* execution information */
283
+ VALUE *stack; /* must free, must mark. rb: seems to be nil. */
284
+ unsigned long stack_size; /* Number of stack (or rb_control_frame_t) entries */
285
+ rb_control_frame_t *cfp;
286
+
287
+ int safe_level;
288
+ int raised_flag;
289
+ VALUE last_status; /* $? */
290
+
291
+ /* passing state */
292
+ int state;
293
+
294
+ /* tracer */
295
+ rb_event_hook_t *event_hooks;
296
+ rb_event_flag_t event_flags;
297
+ int tracing; /* 0 if not tracing. If less than 0, skip that many
298
+ C call/return pairs */
299
+ int exec_event_tracing; /* 0 if not in rb_threadptr_evec_event_hooks. */
300
+ int trace_skip_insn_count; /* # of VM instructions to skip */
301
+
302
+ /* misc */
303
+ int method_missing_reason;
304
+ int abort_on_exception;
305
+
306
+ /* for rb_iterate */
307
+ const rb_block_t *passed_block;
308
+
309
+ /* for bmethod */
310
+ const rb_method_entry_t *passed_me;
311
+
312
+ /* for load(true) */
313
+ VALUE top_self;
314
+ VALUE top_wrapper;
315
+
316
+ /* eval env */
317
+ rb_block_t *base_block;
318
+
319
+ VALUE *local_lfp;
320
+ VALUE local_svar;
321
+
322
+ /* Lot's of other stuff ...
323
+ thread control ... */
324
+ } rb_thread_t;
325
+
326
+ typedef struct {
327
+ rb_block_t block;
328
+
329
+ VALUE envval; /* for GC mark */
330
+ VALUE blockprocval;
331
+ int safe_level;
332
+ int is_from_method;
333
+ int is_lambda;
334
+ } rb_proc_t;
335
+
336
+ #define GetEnvPtr(obj, ptr) \
337
+ GetCoreDataFromValue(obj, rb_env_t, ptr)
338
+
339
+ typedef struct {
340
+ VALUE *env;
341
+ int env_size;
342
+ int local_size;
343
+ VALUE prev_envval; /* for GC mark */
344
+ rb_block_t block;
345
+ } rb_env_t;
346
+
347
+ #define GetBindingPtr(obj, ptr) \
348
+ GetCoreDataFromValue(obj, rb_binding_t, ptr)
349
+
350
+ typedef struct {
351
+ VALUE env;
352
+ VALUE filename;
353
+ unsigned short line_no;
354
+ } rb_binding_t;
355
+
356
+ #define GET_THREAD() ruby_current_thread
357
+ extern rb_thread_t *ruby_current_thread;
data/lib/iseq_extra.rb ADDED
@@ -0,0 +1,89 @@
1
+ require 'digest/sha1'
2
+ require_relative '../ext/thread_frame'
3
+ # Some additions to RubyVM::InstructionSequence
4
+ class RubyVM::InstructionSequence
5
+
6
+ # Turns a instruction sequence type field into a string name
7
+ TYPE2STR = %w(top method block class rescue ensure eval main guard)
8
+
9
+ # Returns a String containing a list of arguments for the RubyVM::InstructionSequence
10
+ # A semicolon separates required arguments from optional ones.
11
+ # For example: for
12
+ # def evaluate(context, statements, file = __FILE__, line = __LINE__)
13
+ # we return:
14
+ # context, statements; file, line
15
+ def format_args
16
+ required_max = arity < 0 ? -arity-1 : arity
17
+ args = 0.upto(required_max-1).map do |i|
18
+ local_name(i)
19
+ end.join(', ')
20
+
21
+ last = local_table_size-1
22
+ if last >= required_max
23
+ opt_args = required_max.upto(last).map do |i|
24
+ local_name(i)
25
+ end.join(', ')
26
+ args += '; ' + opt_args
27
+ else
28
+ args = '?'
29
+ end
30
+ end
31
+
32
+ # Basically hash.invert but since each offset can represent many
33
+ # lines, we have to double loop. FIXME: Is there a more efficient way?
34
+ def lineoffsets
35
+ result = {}
36
+ offsetlines.each do |offset, lines|
37
+ lines.each do |line|
38
+ result[line] ||= []
39
+ result[line] << offset
40
+ end
41
+ end
42
+ result
43
+ end
44
+
45
+ # Return An array of VM instruction byte offsets (Fixnums) for a
46
+ # given line_number.
47
+ def line2offsets(line_number)
48
+ offsetlines.select do |offset, lines|
49
+ lines.member?(line_number)
50
+ end.keys
51
+ end
52
+
53
+ # Returns a cryptographic checksum (in particluar a SHA1) for the
54
+ # encoded bytes of the instruction sequence.
55
+ #
56
+ # ==== Example
57
+ #
58
+ # proc{ 5 }.iseq.sha1 => 'b361a73f9efd7dc4d2c5e86d4e94d40b36141d42'
59
+ def sha1
60
+ Digest::SHA1.hexdigest(encoded)
61
+ end
62
+
63
+ end
64
+
65
+ if __FILE__ == $0
66
+ # Demo it.
67
+ iseq = RubyVM::ThreadFrame.current.iseq
68
+ puts iseq.format_args
69
+ puts iseq.disassemble
70
+ puts iseq.lineoffsets
71
+ puts iseq.sha1
72
+ p iseq.line2offsets(__LINE__)
73
+ p iseq.line2offsets(__LINE__+100)
74
+
75
+ def show_type # :nodoc:
76
+ tf = RubyVM::ThreadFrame.current
77
+ while tf do
78
+ is = tf.iseq
79
+ if is
80
+ ist = tf.iseq.type
81
+ isn = RubyVM::InstructionSequence::TYPE2STR[ist]
82
+ puts "instruction sequence #{is.inspect} has type #{isn} (#{ist})."
83
+ end
84
+ tf = tf.prev
85
+ end
86
+ end
87
+ show_type
88
+ end
89
+