rb-threadframe 0.32
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +23 -0
- data/NEWS +2 -0
- data/README.md +9 -0
- data/Rakefile +162 -0
- data/ext/extconf.rb +12 -0
- data/ext/iseq_extra.c +404 -0
- data/ext/iseq_extra.h +8 -0
- data/ext/iseq_mini.h +41 -0
- data/ext/node.h +483 -0
- data/ext/proc_extra.c +108 -0
- data/ext/proc_extra.h +3 -0
- data/ext/thread_extra.c +84 -0
- data/ext/thread_extra.h +5 -0
- data/ext/thread_frame.c +1022 -0
- data/ext/thread_frame.h +4 -0
- data/ext/thread_pthread.h +24 -0
- data/include/method_mini.h +90 -0
- data/include/node.h +483 -0
- data/include/ruby19_externs.h +36 -0
- data/include/thread_pthread.h +24 -0
- data/include/vm_core_mini.h +357 -0
- data/lib/iseq_extra.rb +89 -0
- data/lib/thread_frame.rb +3 -0
- data/test/unit/cfunc-use.rb +11 -0
- data/test/unit/test-argc.rb +45 -0
- data/test/unit/test-binding.rb +44 -0
- data/test/unit/test-invalid.rb +40 -0
- data/test/unit/test-iseq-brkpt.rb +61 -0
- data/test/unit/test-iseq.rb +121 -0
- data/test/unit/test-lib-iseq-extra.rb +57 -0
- data/test/unit/test-prev.rb +54 -0
- data/test/unit/test-proc.rb +23 -0
- data/test/unit/test-return-stop.rb +64 -0
- data/test/unit/test-settracefunc.rb +315 -0
- data/test/unit/test-source.rb +104 -0
- data/test/unit/test-sp-size.rb +45 -0
- data/test/unit/test-thread-trace-masks.rb +90 -0
- data/test/unit/test-thread.rb +168 -0
- data/test/unit/test-trace.rb +55 -0
- data/threadframe.rd +163 -0
- metadata +110 -0
@@ -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
|
+
|