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.
@@ -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
  }