sender 1.5.9 → 1.5.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,11 @@
1
1
  #ifndef RP_SENDER_GLOBAL
2
- #define RP_SENDER_GLOBAL
2
+ #define RP_SENDER_GLOBAL
3
3
 
4
- #include "RPSender_internal.h"
4
+ #include "RPSender_internal.h"
5
5
 
6
- void Init_senderGlobal();
6
+ void Init_senderGlobal();
7
7
 
8
- VALUE rb_RPRuby_Sender___sender__();
9
- VALUE rb_RPRuby_Sender___caller__();
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
- #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 );
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
@@ -10,25 +10,25 @@
10
10
  * Kernel *
11
11
  ***********/
12
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 );
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 "Enumerators not currently enabled due to difficulty with Fiber support."
27
+ #define RPRUBY_SENDER_ERROR_NO_ENUMERATORS "Enumerators not currently enabled due to difficulty with Fiber support."
28
28
 
29
29
  /***************************************************************************************************************************************************************
30
30
  ****************************************************************************************************************************************************************
31
- Ruby Kernel Methods
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( 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++;
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( 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:
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
- 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;
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( 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:
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
- // 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;
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( 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 );
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( 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 );
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( 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 );
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
- Internal Methods
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( 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;
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
  }