rb-threadframe 0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+