sender 1.5.9 → 1.5.10
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.
- 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
|
}
|