sender 1.5.9 → 1.5.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +278 -278
- data/ext/sender/RPSender_internal.c +23 -23
- data/ext/sender/RPSender_internal.h +9 -9
- data/ext/sender/RubySourceSupport.c +20 -20
- data/ext/sender/RubySourceSupport.h +65 -65
- data/ext/sender/extconf.rb +4 -4
- data/ext/sender/rb_Global.c +107 -107
- data/ext/sender/rb_Global.h +6 -6
- data/ext/sender/rb_Global_internal.h +4 -4
- data/ext/sender/rb_Kernel.c +556 -556
- data/ext/sender/rb_Kernel.h +24 -24
- data/ext/sender/rb_Kernel_internal.h +5 -5
- data/ext/sender/sender.c +6 -6
- metadata +68 -70
data/ext/sender/rb_Global.h
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
#ifndef RP_SENDER_GLOBAL
|
2
|
-
|
2
|
+
#define RP_SENDER_GLOBAL
|
3
3
|
|
4
|
-
|
4
|
+
#include "RPSender_internal.h"
|
5
5
|
|
6
|
-
|
6
|
+
void Init_senderGlobal();
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
VALUE rb_RPRuby_Sender___sender__();
|
9
|
+
VALUE rb_RPRuby_Sender___caller__();
|
10
|
+
|
11
11
|
#endif
|
@@ -1,8 +1,8 @@
|
|
1
1
|
|
2
2
|
#ifndef RP_SENDER_CALLER_GLOBAL_INTERNAL
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
#define RP_SENDER_CALLER_GLOBAL_INTERNAL
|
4
|
+
|
5
|
+
rb_control_frame_t* RPRuby_internal_framePriorTo();
|
6
|
+
rb_control_instruction_t* RPRuby_internal_instructionPriorTo( rb_control_instruction_t* c_control_instruction );
|
7
7
|
|
8
8
|
#endif
|
data/ext/sender/rb_Kernel.c
CHANGED
@@ -10,25 +10,25 @@
|
|
10
10
|
* Kernel *
|
11
11
|
***********/
|
12
12
|
|
13
|
-
void Init_senderKernel()
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
void Init_senderKernel() {
|
14
|
+
|
15
|
+
rb_define_singleton_method( rb_mKernel, "backtrace", rb_RPRuby_Sender_Kernel_backtrace, -1 );
|
16
|
+
rb_define_singleton_method( rb_mKernel, "each_backtrace_frame", rb_RPRuby_Sender_Kernel_each_backtrace_frame, -1 );
|
17
|
+
rb_define_singleton_method( rb_mKernel, "backtrace_includes?", rb_RPRuby_Sender_Kernel_backtrace_includes, -1 );
|
18
|
+
rb_define_singleton_method( rb_mKernel, "backtrace_includes_one_of?", rb_RPRuby_Sender_Kernel_backtrace_includes_one_of, -1 );
|
19
|
+
rb_define_singleton_method( rb_mKernel, "backtrace_frame_with", rb_RPRuby_Sender_Kernel_backtrace_frame_with, -1 );
|
20
|
+
rb_define_singleton_method( rb_mKernel, "backtrace_frames_with", rb_RPRuby_Sender_Kernel_backtrace_frames_with, -1 );
|
21
21
|
|
22
22
|
|
23
23
|
}
|
24
24
|
|
25
25
|
static VALUE rb_eFiberError;
|
26
26
|
|
27
|
-
#define RPRUBY_SENDER_ERROR_NO_ENUMERATORS
|
27
|
+
#define RPRUBY_SENDER_ERROR_NO_ENUMERATORS "Enumerators not currently enabled due to difficulty with Fiber support."
|
28
28
|
|
29
29
|
/***************************************************************************************************************************************************************
|
30
30
|
****************************************************************************************************************************************************************
|
31
|
-
|
31
|
+
Ruby Kernel Methods
|
32
32
|
****************************************************************************************************************************************************************
|
33
33
|
***************************************************************************************************************************************************************/
|
34
34
|
|
@@ -44,54 +44,54 @@ static VALUE rb_eFiberError;
|
|
44
44
|
* Specifying number_of_frames will cause only the last number_of_frames to be returned.
|
45
45
|
* Kernel.backtrace returns all frames including the current context (__method__/__callee__).
|
46
46
|
*/
|
47
|
-
VALUE rb_RPRuby_Sender_Kernel_backtrace(
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
rb_control_frame_t*
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
while (
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
47
|
+
VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
|
48
|
+
VALUE* args,
|
49
|
+
VALUE rb_self ) {
|
50
|
+
|
51
|
+
// Get max stack level from args if it is there
|
52
|
+
int c_max_stack_level = 0;
|
53
|
+
if ( argc ) {
|
54
|
+
c_max_stack_level = FIX2INT( args[ 0 ] );
|
55
|
+
|
56
|
+
// if max_stack_level is 0 return empty array
|
57
|
+
if ( c_max_stack_level == 0 ) {
|
58
|
+
return rb_ary_new();
|
59
|
+
}
|
60
|
+
// if max_stack_level < 0, throw error
|
61
|
+
else if ( c_max_stack_level < 0 ) {
|
62
|
+
rb_raise( rb_eArgError, RPRUBY_SENDER_ERROR_STACK_LEVEL_LESS_THAN_ZERO );
|
63
|
+
}
|
64
|
+
|
65
|
+
}
|
66
|
+
|
67
|
+
rb_thread_t* c_thread = (rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current());
|
68
|
+
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
|
69
|
+
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp );
|
70
|
+
|
71
|
+
// c_top_of_control_frame describes the top edge of the stack trace
|
72
|
+
// set c_top_of_control_frame to the first frame in <main>
|
73
|
+
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
|
74
|
+
|
75
|
+
VALUE rb_return_array = rb_ary_new();
|
76
|
+
|
77
|
+
int c_stack_level = 0;
|
78
|
+
// for each control frame:
|
79
|
+
while ( c_current_context_frame < c_top_of_control_frame
|
80
|
+
&& ( argc == 0
|
81
|
+
|| c_stack_level < c_max_stack_level ) ) {
|
82
|
+
|
83
|
+
VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
|
84
|
+
|
85
|
+
if ( rb_frame_hash == Qnil ) {
|
86
|
+
break;
|
87
|
+
}
|
88
|
+
|
89
|
+
// push hash to array
|
90
|
+
rb_ary_push( rb_return_array,
|
91
|
+
rb_frame_hash );
|
92
|
+
|
93
|
+
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
|
94
|
+
c_stack_level++;
|
95
95
|
}
|
96
96
|
|
97
97
|
return rb_return_array;
|
@@ -109,67 +109,67 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
|
|
109
109
|
* Specifying number_of_frames will cause only the last number_of_frames to be returned.
|
110
110
|
* Kernel.backtrace returns all frames including the current context (__method__/__callee__).
|
111
111
|
*/
|
112
|
-
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame(
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
rb_control_frame_t*
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
112
|
+
VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
|
113
|
+
VALUE* args,
|
114
|
+
VALUE rb_self ) {
|
115
|
+
|
116
|
+
rb_thread_t* c_thread = (rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current());
|
117
|
+
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
|
118
|
+
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
|
119
|
+
|
120
|
+
// c_top_of_control_frame describes the top edge of the stack trace
|
121
|
+
// set c_top_of_control_frame to the first frame in <main>
|
122
|
+
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
|
123
|
+
|
124
|
+
VALUE rb_stored_backtrace_array = Qnil;
|
125
|
+
|
126
|
+
// if we were passed a stored backtrace array, use it
|
127
|
+
if ( argc == 1
|
128
|
+
&& TYPE( args[ 0 ] ) == T_ARRAY ) {
|
129
|
+
rb_stored_backtrace_array = args[ 0 ];
|
130
|
+
}
|
131
|
+
|
132
|
+
// for each control frame:
|
133
133
|
while ( c_current_context_frame < c_top_of_control_frame ) {
|
134
134
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
135
|
+
VALUE rb_frame_hash;
|
136
|
+
// if we are using a stored backtrace we don't need to ask for a new hash
|
137
|
+
if ( rb_stored_backtrace_array == Qnil ) {
|
138
|
+
rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
|
139
|
+
}
|
140
|
+
else {
|
141
|
+
rb_frame_hash = rb_ary_shift( rb_stored_backtrace_array );
|
142
|
+
}
|
143
|
+
|
144
|
+
if ( rb_frame_hash == Qnil ) {
|
145
|
+
break;
|
146
|
+
}
|
147
|
+
|
148
|
+
// if we try to iterate using an Enumerator we will lose our context
|
149
|
+
if ( ! rb_block_given_p() ) {
|
150
|
+
|
151
|
+
// we solve this by assuming that the desired context is the moment when each_backtrace_frame is called
|
152
|
+
// this allows us to store the backtrace and iterate it as we want
|
153
|
+
// the only downside is that we have to get the entire backtrace first in order to store it
|
154
|
+
rb_stored_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0,
|
155
|
+
NULL,
|
156
|
+
rb_self );
|
157
|
+
|
158
|
+
RETURN_ENUMERATOR( rb_self, 1, & rb_stored_backtrace_array );
|
159
|
+
}
|
160
|
+
|
161
|
+
// otherwise, yield the block
|
162
|
+
rb_yield( rb_frame_hash );
|
163
|
+
|
164
|
+
// only move the frame if we are not using a stored backtrace
|
165
|
+
if ( rb_stored_backtrace_array == Qnil ) {
|
166
|
+
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
return Qnil;
|
171
171
|
}
|
172
|
-
|
172
|
+
|
173
173
|
/********************************
|
174
174
|
* Kernel.backtrace_includes? *
|
175
175
|
*******************************/
|
@@ -183,257 +183,257 @@ VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
|
|
183
183
|
* Kernel.backtrace_includes? begins with the prior frame, so asking if the backtrace includes the current method
|
184
184
|
* will only report true if the current method is part of the earlier call chain.
|
185
185
|
*/
|
186
|
-
VALUE rb_RPRuby_Sender_Kernel_backtrace_includes(
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
rb_control_frame_t*
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
186
|
+
VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
|
187
|
+
VALUE* args,
|
188
|
+
VALUE rb_self ) {
|
189
|
+
|
190
|
+
// this function is also used for
|
191
|
+
// * backtrace_includes_one_of?
|
192
|
+
// * backtrace_includes_frame?
|
193
|
+
// * backtrace_includes_one_of_frames?
|
194
|
+
|
195
|
+
// create tracking array
|
196
|
+
VALUE rb_tracking_array = rb_ary_new();
|
197
|
+
|
198
|
+
// populate tracking array with methods/objects
|
199
|
+
// optional - if first arg is Qtrue, we are looking for one of the args instead of all of the args
|
200
|
+
int c_which_arg = 0;
|
201
|
+
BOOL c_requires_all_items = TRUE;
|
202
|
+
if ( args[ 0 ] == Qnil
|
203
|
+
|| ( argc > 1
|
204
|
+
&& args[ 1 ] == Qnil ) ) {
|
205
|
+
c_which_arg++;
|
206
|
+
c_requires_all_items = FALSE;
|
207
|
+
}
|
208
|
+
BOOL c_return_frame = FALSE;
|
209
|
+
if ( args[ 0 ] == Qfalse
|
210
|
+
|| ( argc > 1
|
211
|
+
&& args[ 1 ] == Qfalse ) ) {
|
212
|
+
c_which_arg++;
|
213
|
+
c_return_frame = TRUE;
|
214
|
+
}
|
215
|
+
BOOL c_return_all_frames = FALSE;
|
216
|
+
if ( args[ 0 ] == Qtrue
|
217
|
+
|| ( argc > 1
|
218
|
+
&& args[ 1 ] == Qtrue ) ) {
|
219
|
+
c_which_arg++;
|
220
|
+
c_return_all_frames = TRUE;
|
221
|
+
}
|
222
|
+
int c_args_offset = c_which_arg;
|
223
|
+
for ( ; c_which_arg < argc ; c_which_arg++ ) {
|
224
|
+
rb_ary_push( rb_tracking_array,
|
225
|
+
args[ c_which_arg ] );
|
226
|
+
}
|
227
|
+
|
228
|
+
rb_thread_t* c_thread = (rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current());
|
229
|
+
// Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
|
230
|
+
rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
|
231
|
+
|
232
|
+
// c_top_of_control_frame describes the top edge of the stack trace
|
233
|
+
// set c_top_of_control_frame to the first frame in <main>
|
234
|
+
rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
|
235
|
+
|
236
|
+
VALUE rb_test_index_array = rb_ary_new();
|
237
|
+
// :object
|
238
|
+
// instance or class
|
239
|
+
rb_ary_push( rb_test_index_array,
|
240
|
+
ID2SYM( rb_intern( "object" ) ) );
|
241
|
+
// :method
|
242
|
+
rb_ary_push( rb_test_index_array,
|
243
|
+
ID2SYM( rb_intern( "method" ) ) );
|
244
|
+
// :file
|
245
|
+
rb_ary_push( rb_test_index_array,
|
246
|
+
ID2SYM( rb_intern( "file" ) ) );
|
247
|
+
// :line
|
248
|
+
rb_ary_push( rb_test_index_array,
|
249
|
+
ID2SYM( rb_intern( "line" ) ) );
|
250
|
+
|
251
|
+
// only used if c_return_all_frames == TRUE
|
252
|
+
VALUE rb_frame_hashes_array = Qnil;
|
253
|
+
if ( c_return_all_frames == TRUE ) {
|
254
|
+
rb_frame_hashes_array = rb_ary_new();
|
255
|
+
}
|
256
|
+
|
257
|
+
VALUE rb_frame_hash = Qnil;
|
258
|
+
|
259
|
+
// for each control frame:
|
260
260
|
while ( c_current_context_frame < c_top_of_control_frame ) {
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
261
|
+
|
262
|
+
// iterate each array member
|
263
|
+
int c_which_member;
|
264
|
+
for ( c_which_member = 0 ; c_which_member < RARRAY_LEN( rb_tracking_array ) ; c_which_member++ ) {
|
265
|
+
|
266
|
+
VALUE rb_this_arg = args[ c_which_member + c_args_offset ];
|
267
|
+
|
268
|
+
BOOL matched = FALSE;
|
269
|
+
|
270
|
+
rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
|
271
|
+
|
272
|
+
// if we have a hash we are testing multiple items in a frame
|
273
|
+
if ( TYPE( rb_this_arg ) == T_HASH ) {
|
274
|
+
|
275
|
+
VALUE rb_frame_test_array = rb_obj_clone( rb_test_index_array );
|
276
|
+
|
277
|
+
// for each element that we could test for
|
278
|
+
int c_which_index;
|
279
|
+
int c_skipped_index_count = 0;
|
280
|
+
for ( c_which_index = 0 ; c_which_index < RARRAY_LEN( rb_frame_test_array ) ; c_which_index++ ) {
|
281
|
+
|
282
|
+
VALUE rb_this_index = RARRAY_PTR( rb_frame_test_array )[ c_which_index ];
|
283
|
+
|
284
|
+
// see if our requested test hash includes the potential test element
|
285
|
+
if ( rb_hash_lookup( rb_this_arg,
|
286
|
+
rb_this_index ) != Qnil ) {
|
287
|
+
|
288
|
+
VALUE rb_required_element = rb_hash_aref( rb_this_arg,
|
289
|
+
rb_this_index );
|
290
|
+
VALUE rb_frame_element = rb_hash_aref( rb_frame_hash,
|
291
|
+
rb_this_index );
|
292
|
+
|
293
|
+
// if it does, we need to see if the current frame's element matches this element
|
294
|
+
VALUE rb_required_element_klass;
|
295
|
+
if ( rb_required_element == rb_frame_element
|
296
|
+
// if we have a string, which is a filename
|
297
|
+
|| ( TYPE( rb_required_element ) == T_STRING
|
298
|
+
&& rb_funcall( rb_frame_element, rb_intern( "==" ), 1, rb_required_element ) == Qtrue )
|
299
|
+
// if we have a class, which is a special case for :object
|
300
|
+
|| ( rb_this_index == ID2SYM( rb_intern( "class" ) )
|
301
|
+
&& ( rb_required_element_klass = ( ( TYPE( rb_required_element ) == T_CLASS ) ? rb_required_element : rb_funcall( rb_required_element, rb_intern( "class" ), 0 ) ) )
|
302
|
+
&& rb_required_element_klass == rb_required_element ) ) {
|
303
|
+
|
304
|
+
rb_ary_delete_at( rb_frame_test_array,
|
305
|
+
c_which_index );
|
306
|
+
c_which_index--;
|
307
|
+
}
|
308
|
+
}
|
309
|
+
else {
|
310
|
+
c_skipped_index_count++;
|
311
|
+
}
|
312
|
+
|
313
|
+
if ( RARRAY_LEN( rb_frame_test_array ) == c_skipped_index_count ) {
|
314
|
+
if ( c_return_frame == TRUE ) {
|
315
|
+
return rb_frame_hash;
|
316
|
+
}
|
317
|
+
else if ( c_return_all_frames == TRUE ) {
|
318
|
+
rb_ary_push( rb_frame_hashes_array,
|
319
|
+
rb_frame_hash );
|
320
|
+
}
|
321
|
+
else {
|
322
|
+
return Qtrue;
|
323
|
+
}
|
324
|
+
}
|
325
|
+
}
|
326
|
+
}
|
327
|
+
else {
|
328
|
+
|
329
|
+
// :object => <class:instance>
|
330
|
+
if ( TYPE( rb_this_arg ) == T_OBJECT ) {
|
331
|
+
|
332
|
+
if ( rb_hash_aref( rb_frame_hash,
|
333
|
+
ID2SYM( rb_intern( "object" ) ) ) == rb_this_arg ) {
|
334
|
+
matched = TRUE;
|
335
|
+
}
|
336
|
+
}
|
337
|
+
// :object => <class>
|
338
|
+
else if ( TYPE( rb_this_arg ) == T_CLASS ) {
|
339
|
+
|
340
|
+
VALUE rb_frame_object = rb_hash_aref( rb_frame_hash,
|
341
|
+
ID2SYM( rb_intern( "object" ) ) );
|
342
|
+
VALUE rb_frame_object_klass = TYPE( rb_frame_object ) == T_CLASS ? rb_frame_object : rb_funcall( rb_frame_object, rb_intern( "class" ), 0 );
|
343
|
+
if ( rb_frame_object_klass == rb_this_arg ) {
|
344
|
+
matched = TRUE;
|
345
|
+
}
|
346
|
+
}
|
347
|
+
// :method => :method
|
348
|
+
else if ( TYPE( rb_this_arg ) == T_SYMBOL ) {
|
349
|
+
|
350
|
+
if ( rb_hash_aref( rb_frame_hash,
|
351
|
+
ID2SYM( rb_intern( "method" ) ) ) == rb_this_arg ) {
|
352
|
+
matched = TRUE;
|
353
|
+
}
|
354
|
+
}
|
355
|
+
// :file => "filename"
|
356
|
+
else if ( TYPE( rb_this_arg ) == T_STRING ) {
|
357
|
+
VALUE rb_filename = rb_hash_aref( rb_frame_hash,
|
358
|
+
ID2SYM( rb_intern( "file" ) ) );
|
359
|
+
VALUE rb_comparison = rb_funcall( rb_filename, rb_intern( "==" ), 1, rb_this_arg );
|
360
|
+
if ( rb_comparison == Qtrue ) {
|
361
|
+
matched = TRUE;
|
362
|
+
}
|
363
|
+
}
|
364
|
+
// :line => number
|
365
|
+
else if ( TYPE( rb_this_arg ) == T_FIXNUM ) {
|
366
|
+
if ( rb_hash_aref( rb_frame_hash,
|
367
|
+
ID2SYM( rb_intern( "line" ) ) ) == rb_this_arg ) {
|
368
|
+
matched = TRUE;
|
369
|
+
}
|
370
|
+
}
|
371
|
+
|
372
|
+
// if array member exists in frame, remove from array
|
373
|
+
if ( matched ) {
|
374
|
+
if ( c_requires_all_items == FALSE ) {
|
375
|
+
if ( c_return_frame == TRUE ) {
|
376
|
+
return rb_frame_hash;
|
377
|
+
}
|
378
|
+
else {
|
379
|
+
return Qtrue;
|
380
|
+
}
|
381
|
+
|
382
|
+
}
|
383
|
+
else {
|
384
|
+
|
385
|
+
// delete this index
|
386
|
+
rb_ary_delete_at( rb_tracking_array,
|
387
|
+
c_which_member );
|
388
|
+
|
389
|
+
// decrement the loop iterator so that the increase is offset
|
390
|
+
// this is necessary since we just removed an index and are iterating vs. the length of the array
|
391
|
+
c_which_member--;
|
392
|
+
}
|
393
|
+
}
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
// if array is empty, return true
|
398
|
+
// we check here as well as at the end so we can stop iterating the backtrace if we find all our items
|
399
|
+
if ( RARRAY_LEN( rb_tracking_array ) == 0 ) {
|
400
|
+
if ( c_return_frame == TRUE ) {
|
401
|
+
return rb_frame_hash;
|
402
|
+
}
|
403
|
+
else if ( c_return_all_frames == TRUE ) {
|
404
|
+
rb_ary_push( rb_frame_hashes_array,
|
405
|
+
rb_frame_hash );
|
406
|
+
return rb_frame_hashes_array;
|
407
|
+
}
|
408
|
+
else {
|
409
|
+
return Qtrue;
|
410
|
+
}
|
411
|
+
}
|
412
|
+
c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
|
413
|
+
}
|
414
|
+
|
415
|
+
if ( c_return_all_frames == TRUE
|
416
|
+
&& RARRAY_LEN( rb_frame_hashes_array ) > 0 ) {
|
417
|
+
return rb_frame_hashes_array;
|
418
|
+
}
|
419
|
+
// if we finish iterating frames and still have items in the array, return false
|
420
|
+
else if ( RARRAY_LEN( rb_tracking_array ) > 0 ) {
|
421
|
+
if ( c_return_frame == TRUE ) {
|
422
|
+
return Qnil;
|
423
|
+
}
|
424
|
+
else {
|
425
|
+
return Qfalse;
|
426
|
+
}
|
427
|
+
}
|
428
|
+
// otherwise, return true
|
429
|
+
else if ( c_return_frame == TRUE ) {
|
430
|
+
return rb_frame_hash;
|
431
|
+
}
|
432
|
+
else {
|
433
|
+
return Qtrue;
|
434
|
+
}
|
435
|
+
// we don't get here
|
436
|
+
return Qnil;
|
437
437
|
}
|
438
438
|
|
439
439
|
/***************************************
|
@@ -449,22 +449,22 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
|
|
449
449
|
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
450
450
|
* will only report true if the current method is part of the earlier call chain.
|
451
451
|
*/
|
452
|
-
VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of(
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
452
|
+
VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( int argc,
|
453
|
+
VALUE* args,
|
454
|
+
VALUE rb_self ) {
|
455
|
+
|
456
|
+
// method implemented as special case of backtrace_includes?
|
457
|
+
|
458
|
+
// create a new array starting with Qtrue and then followed by args
|
459
|
+
VALUE c_methods_array[ argc + 1 ];
|
460
|
+
c_methods_array[ 0 ] = Qnil;
|
461
|
+
int c_which_arg;
|
462
|
+
for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
|
463
|
+
c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
|
464
|
+
}
|
465
|
+
return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
|
466
|
+
c_methods_array,
|
467
|
+
rb_self );
|
468
468
|
}
|
469
469
|
|
470
470
|
/*********************************
|
@@ -480,21 +480,21 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( int argc,
|
|
480
480
|
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
481
481
|
* will only report true if the current method is part of the earlier call chain.
|
482
482
|
*/
|
483
|
-
VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with(
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
483
|
+
VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with( int argc,
|
484
|
+
VALUE* args,
|
485
|
+
VALUE rb_self ) {
|
486
|
+
|
487
|
+
// create a new array starting with Qtrue and then followed by args
|
488
|
+
VALUE c_methods_array[ argc + 1 ];
|
489
|
+
// Qfalse tells backtrace_includes to return frame hash instead of true/false
|
490
|
+
c_methods_array[ 0 ] = Qfalse;
|
491
|
+
int c_which_arg;
|
492
|
+
for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
|
493
|
+
c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
|
494
|
+
}
|
495
|
+
return rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( argc + 1,
|
496
|
+
c_methods_array,
|
497
|
+
rb_self );
|
498
498
|
}
|
499
499
|
|
500
500
|
/**********************************
|
@@ -510,27 +510,27 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with( int argc,
|
|
510
510
|
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
511
511
|
* will only report true if the current method is part of the earlier call chain.
|
512
512
|
*/
|
513
|
-
VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with(
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
513
|
+
VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with( int argc,
|
514
|
+
VALUE* args,
|
515
|
+
VALUE rb_self ) {
|
516
|
+
|
517
|
+
|
518
|
+
// create a new array starting with Qtrue and then followed by args
|
519
|
+
VALUE c_methods_array[ argc + 1 ];
|
520
|
+
// Qtrue tells backtrace_includes to return all frame hashes specified instead of the first
|
521
|
+
c_methods_array[ 0 ] = Qtrue;
|
522
|
+
int c_which_arg;
|
523
|
+
for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
|
524
|
+
c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
|
525
|
+
}
|
526
|
+
return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
|
527
|
+
c_methods_array,
|
528
|
+
rb_self );
|
529
529
|
}
|
530
530
|
|
531
531
|
/***************************************************************************************************************************************************************
|
532
532
|
****************************************************************************************************************************************************************
|
533
|
-
|
533
|
+
Internal Methods
|
534
534
|
****************************************************************************************************************************************************************
|
535
535
|
***************************************************************************************************************************************************************/
|
536
536
|
|
@@ -538,146 +538,146 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with( int argc,
|
|
538
538
|
* backtraceHashForControlFrame *
|
539
539
|
*********************************/
|
540
540
|
|
541
|
-
VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame(
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
//
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
541
|
+
VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_frame_t** c_current_frame ) {
|
542
|
+
|
543
|
+
const char* c_method_name = NULL;
|
544
|
+
int c_sourcefile_line = 0;
|
545
|
+
|
546
|
+
// create new hash for this frame
|
547
|
+
VALUE rb_frame_hash = rb_hash_new();
|
548
|
+
|
549
|
+
VALUE rb_sourcefile_name = Qnil;
|
550
|
+
VALUE rb_sourcefile_line = Qnil;
|
551
|
+
VALUE rb_method_name = Qnil;
|
552
|
+
VALUE rb_object_for_frame = Qnil;
|
553
|
+
|
554
|
+
if ( ( *c_current_frame )->iseq != 0 ) {
|
555
|
+
|
556
|
+
if ( ( *c_current_frame )->pc != 0 ) {
|
557
|
+
|
558
|
+
rb_iseq_t *iseq = ( *c_current_frame )->iseq;
|
559
|
+
|
560
|
+
// get sourcefile name and set in hash
|
561
|
+
rb_sourcefile_name = iseq->filename;
|
562
|
+
|
563
|
+
// get sourcefile line and set in hash
|
564
|
+
c_sourcefile_line = rb_vm_get_sourceline( *c_current_frame );
|
565
|
+
rb_sourcefile_line = INT2FIX( c_sourcefile_line );
|
566
|
+
|
567
|
+
// get name of instruction sequence
|
568
|
+
rb_method_name = ID2SYM( rb_intern( StringValuePtr( iseq->name ) ) );
|
569
|
+
rb_object_for_frame = ( *c_current_frame )->self;
|
570
|
+
}
|
571
|
+
}
|
572
|
+
else if ( RUBYVM_CFUNC_FRAME_P( *c_current_frame ) ) {
|
573
|
+
|
574
|
+
// get name of method
|
575
|
+
|
576
|
+
#if RUBY_PATCHLEVEL >= -1
|
577
|
+
// For 1.9.2:
|
578
|
+
const rb_method_entry_t* c_method_for_frame = ( *c_current_frame )->me;
|
579
|
+
c_method_name = rb_id2name( c_method_for_frame->called_id );
|
580
|
+
#else
|
581
|
+
// For 1.9.1:
|
582
|
+
c_method_name = rb_id2name( ( *c_current_frame )->method_id );
|
583
|
+
#endif
|
584
|
+
|
585
|
+
rb_method_name = ( c_method_name == NULL ? Qnil : ID2SYM( rb_intern( c_method_name ) ) );
|
586
|
+
rb_object_for_frame = ( *c_current_frame )->self;
|
587
|
+
}
|
588
|
+
// we have to test this case - it works for blocks but there may be other cases too
|
589
|
+
else if ( ( *c_current_frame )->block_iseq != 0
|
590
|
+
&& ( *c_current_frame )->pc == 0) {
|
591
|
+
|
592
|
+
// If we got here we have a fiber
|
593
|
+
// There doesn't seem to be much that we can tell about a fiber's context
|
594
|
+
|
595
|
+
VALUE rb_current_fiber = rb_fiber_current();
|
596
|
+
rb_fiber_t* c_current_fiber = NULL;
|
597
|
+
|
598
|
+
GetFiberPtr( rb_current_fiber,
|
599
|
+
c_current_fiber);
|
600
|
+
|
601
|
+
rb_context_t* c_context = & c_current_fiber->cont;
|
602
|
+
|
603
|
+
// rb_block_t* c_blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP( *c_current_frame );
|
604
|
+
|
605
|
+
rb_object_for_frame = ( *c_current_frame )->self;
|
606
|
+
|
607
|
+
// get sourcefile name and set in hash
|
608
|
+
rb_sourcefile_name = Qnil;
|
609
|
+
|
610
|
+
// get sourcefile line and set in hash
|
611
|
+
rb_sourcefile_line = Qnil;
|
612
|
+
|
613
|
+
// get name of instruction sequence
|
614
|
+
rb_method_name = rb_str_new2( "<Fiber>" );
|
615
|
+
|
616
|
+
// if we have a fiber we also include its ruby reference since we have so little other context
|
617
|
+
rb_hash_aset( rb_frame_hash,
|
618
|
+
ID2SYM( rb_intern( "fiber" ) ),
|
619
|
+
c_context->self );
|
620
|
+
|
621
|
+
// The one time that we know a fiber is in use in the Ruby base is with Enumerators
|
622
|
+
// For now we will handle that with a special case
|
623
|
+
|
624
|
+
VALUE rb_enumerator_class = rb_const_get( rb_cObject,
|
625
|
+
rb_intern( "Enumerator" ) );
|
626
|
+
|
627
|
+
VALUE rb_object_for_frame_klass = ( ( TYPE( rb_object_for_frame ) == T_CLASS ) ? rb_object_for_frame : rb_funcall( rb_object_for_frame, rb_intern( "class" ), 0 ) );
|
628
|
+
|
629
|
+
VALUE rb_ancestors = rb_funcall( rb_object_for_frame_klass,
|
630
|
+
rb_intern( "ancestors" ),
|
631
|
+
0 );
|
632
|
+
|
633
|
+
if ( rb_ary_includes( rb_ancestors,
|
634
|
+
rb_enumerator_class ) ) {
|
635
|
+
|
636
|
+
struct enumerator* c_enumerator = enumerator_ptr( rb_object_for_frame );
|
637
|
+
|
638
|
+
rb_object_for_frame = c_enumerator->obj;
|
639
|
+
rb_method_name = ID2SYM( c_enumerator->meth );
|
640
|
+
}
|
641
|
+
|
642
|
+
}
|
643
|
+
else if ( ( *c_current_frame )->block_iseq == 0
|
644
|
+
&& ( *c_current_frame )->pc == 0) {
|
645
|
+
// this happens after we had a fiber and we try to go up - which doesn't make sense with a fiber
|
646
|
+
// not sure what we want to do here, if anything
|
647
|
+
return Qnil;
|
648
|
+
}
|
649
|
+
else {
|
650
|
+
// The third possibility is that we have an iseq frame with nil params for what we want
|
651
|
+
// In that case we can simply return the next frame
|
652
|
+
*c_current_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( *c_current_frame );
|
653
|
+
|
654
|
+
// in theory this could crash because we are going forward a frame when we don't know what's there
|
655
|
+
// in practice I think we are ok, since we are only jumping forward from nil frames which should never be at the end
|
656
|
+
// at least - I don't think they should... we shall see.
|
657
|
+
//
|
658
|
+
// a fix would be to check the next frame, but that requires access to the thread or the limit cfp,
|
659
|
+
// which requires passing more context; so for now, I'm leaving it there
|
660
|
+
|
661
|
+
return rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( c_current_frame );
|
662
|
+
}
|
663
|
+
|
664
|
+
// Push values to return hash
|
665
|
+
|
666
|
+
rb_hash_aset( rb_frame_hash,
|
667
|
+
ID2SYM( rb_intern( "object" ) ),
|
668
|
+
rb_object_for_frame );
|
669
|
+
|
670
|
+
rb_hash_aset( rb_frame_hash,
|
671
|
+
ID2SYM( rb_intern( "file" ) ),
|
672
|
+
rb_sourcefile_name );
|
673
|
+
|
674
|
+
rb_hash_aset( rb_frame_hash,
|
675
|
+
ID2SYM( rb_intern( "line" ) ),
|
676
|
+
rb_sourcefile_line );
|
677
|
+
|
678
|
+
rb_hash_aset( rb_frame_hash,
|
679
|
+
ID2SYM( rb_intern( "method" ) ),
|
680
|
+
rb_method_name );
|
681
|
+
|
682
|
+
return rb_frame_hash;
|
683
683
|
}
|