sender 1.5.4 → 1.5.5
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.
- metadata +19 -90
- data/.autotest +0 -11
- data/CHANGELOG.rdoc +0 -72
- data/Manifest.txt +0 -24
- data/Rakefile +0 -25
- data/VERSION.rdoc +0 -1
- data/ext/sender/RPSender_internal.c +0 -37
- data/ext/sender/RPSender_internal.h +0 -15
- data/ext/sender/RubySourceSupport.c +0 -47
- data/ext/sender/RubySourceSupport.h +0 -77
- data/ext/sender/rb_Global.c +0 -151
- data/ext/sender/rb_Global.h +0 -11
- data/ext/sender/rb_Global_internal.h +0 -8
- data/ext/sender/rb_Kernel.c +0 -683
- data/ext/sender/rb_Kernel.h +0 -31
- data/ext/sender/rb_Kernel_internal.h +0 -10
- data/ext/sender/sender.c +0 -16
- data/lib/sender/sender.bundle +0 -0
- data/mkmf.log +0 -69
- data/sender.gemspec +0 -51
- data/test/test_sender.rb +0 -22
data/ext/sender/rb_Kernel.c
DELETED
|
@@ -1,683 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
#include "rb_Kernel.h"
|
|
3
|
-
#include "rb_Kernel_internal.h"
|
|
4
|
-
|
|
5
|
-
#include "RPSender_internal.h"
|
|
6
|
-
|
|
7
|
-
#include "RubySourceSupport.h"
|
|
8
|
-
|
|
9
|
-
/***********
|
|
10
|
-
* Kernel *
|
|
11
|
-
***********/
|
|
12
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static VALUE rb_eFiberError;
|
|
26
|
-
|
|
27
|
-
#define RPRUBY_SENDER_ERROR_NO_ENUMERATORS "Enumerators not currently enabled due to difficulty with Fiber support."
|
|
28
|
-
|
|
29
|
-
/***************************************************************************************************************************************************************
|
|
30
|
-
****************************************************************************************************************************************************************
|
|
31
|
-
Ruby Kernel Methods
|
|
32
|
-
****************************************************************************************************************************************************************
|
|
33
|
-
***************************************************************************************************************************************************************/
|
|
34
|
-
|
|
35
|
-
/**********************
|
|
36
|
-
* Kernel.backtrace *
|
|
37
|
-
*********************/
|
|
38
|
-
|
|
39
|
-
/*
|
|
40
|
-
* call-seq:
|
|
41
|
-
* Kernel.backtrace( number_of_frames = nil ) -> [ { :object => object, :method => method }, ... ]
|
|
42
|
-
*
|
|
43
|
-
* Return array of hashes with object and method frame information for backtrace.
|
|
44
|
-
* Specifying number_of_frames will cause only the last number_of_frames to be returned.
|
|
45
|
-
* Kernel.backtrace returns all frames including the current context (__method__/__callee__).
|
|
46
|
-
*/
|
|
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 = GET_THREAD();
|
|
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
|
-
}
|
|
96
|
-
|
|
97
|
-
return rb_return_array;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/*********************************
|
|
101
|
-
* Kernel.each_backtrace_frame *
|
|
102
|
-
********************************/
|
|
103
|
-
|
|
104
|
-
/*
|
|
105
|
-
* call-seq:
|
|
106
|
-
* Kernel.each_backtrace_frame( & block )
|
|
107
|
-
*
|
|
108
|
-
* Return array of hashes with object and method frame information for backtrace.
|
|
109
|
-
* Specifying number_of_frames will cause only the last number_of_frames to be returned.
|
|
110
|
-
* Kernel.backtrace returns all frames including the current context (__method__/__callee__).
|
|
111
|
-
*/
|
|
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 = GET_THREAD();
|
|
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
|
-
while ( c_current_context_frame < c_top_of_control_frame ) {
|
|
134
|
-
|
|
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
|
-
}
|
|
172
|
-
|
|
173
|
-
/********************************
|
|
174
|
-
* Kernel.backtrace_includes? *
|
|
175
|
-
*******************************/
|
|
176
|
-
|
|
177
|
-
/*
|
|
178
|
-
* call-seq:
|
|
179
|
-
* Kernel.backtrace_includes?( method_or_object, ... ) -> true or false
|
|
180
|
-
* Kernel.backtrace_includes?( number_of_frames, method_or_object, ... ) -> true or false
|
|
181
|
-
*
|
|
182
|
-
* Returns whether specified methods or objects or classes are in the current backtrace context.
|
|
183
|
-
* Kernel.backtrace_includes? begins with the prior frame, so asking if the backtrace includes the current method
|
|
184
|
-
* will only report true if the current method is part of the earlier call chain.
|
|
185
|
-
*/
|
|
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 = GET_THREAD();
|
|
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
|
-
while ( c_current_context_frame < c_top_of_control_frame ) {
|
|
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
|
-
}
|
|
438
|
-
|
|
439
|
-
/***************************************
|
|
440
|
-
* Kernel.backtrace_includes_one_of? *
|
|
441
|
-
**************************************/
|
|
442
|
-
|
|
443
|
-
/*
|
|
444
|
-
* call-seq:
|
|
445
|
-
* Kernel.backtrace_includes_one_of?( method_or_object, ... ) -> true or false
|
|
446
|
-
* Kernel.backtrace_includes_one_of?( number_of_frames, method_or_object, ... ) -> true or false
|
|
447
|
-
*
|
|
448
|
-
* Returns whether one of the specified methods or objects or classes are in the current backtrace context.
|
|
449
|
-
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
|
450
|
-
* will only report true if the current method is part of the earlier call chain.
|
|
451
|
-
*/
|
|
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
|
-
}
|
|
469
|
-
|
|
470
|
-
/*********************************
|
|
471
|
-
* Kernel.backtrace_frame_with *
|
|
472
|
-
********************************/
|
|
473
|
-
|
|
474
|
-
/*
|
|
475
|
-
* call-seq:
|
|
476
|
-
* Kernel.backtrace_frame_with( method_or_object, ... ) -> true or false
|
|
477
|
-
* Kernel.backtrace_frame_with( number_of_frames, method_or_object, ... ) -> true or false
|
|
478
|
-
*
|
|
479
|
-
* Returns first frame matching specifications, which work like Kernel.backtrace_includes?.
|
|
480
|
-
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
|
481
|
-
* will only report true if the current method is part of the earlier call chain.
|
|
482
|
-
*/
|
|
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
|
-
}
|
|
499
|
-
|
|
500
|
-
/**********************************
|
|
501
|
-
* Kernel.backtrace_frames_with *
|
|
502
|
-
*********************************/
|
|
503
|
-
|
|
504
|
-
/*
|
|
505
|
-
* call-seq:
|
|
506
|
-
* Kernel.backtrace_frames_with( method_or_object, ... ) -> true or false
|
|
507
|
-
* Kernel.backtrace_frames_with( number_of_frames, method_or_object, ... ) -> true or false
|
|
508
|
-
*
|
|
509
|
-
* Returns all frames matching specifications, which work like Kernel.backtrace_includes?.
|
|
510
|
-
* Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
|
|
511
|
-
* will only report true if the current method is part of the earlier call chain.
|
|
512
|
-
*/
|
|
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
|
-
}
|
|
530
|
-
|
|
531
|
-
/***************************************************************************************************************************************************************
|
|
532
|
-
****************************************************************************************************************************************************************
|
|
533
|
-
Internal Methods
|
|
534
|
-
****************************************************************************************************************************************************************
|
|
535
|
-
***************************************************************************************************************************************************************/
|
|
536
|
-
|
|
537
|
-
/**********************************
|
|
538
|
-
* backtraceHashForControlFrame *
|
|
539
|
-
*********************************/
|
|
540
|
-
|
|
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
|
-
}
|