rice 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Doxyfile +1 -1
  2. data/Makefile.in +130 -52
  3. data/README +45 -79
  4. data/Rakefile +1 -36
  5. data/aclocal.m4 +133 -61
  6. data/config.guess +43 -8
  7. data/config.sub +41 -13
  8. data/configure +1370 -1898
  9. data/configure.ac +2 -2
  10. data/doxygen.ac +1 -1
  11. data/extconf.rb +3 -1
  12. data/rice/Arg_impl.hpp +2 -2
  13. data/rice/Data_Type.cpp +34 -1
  14. data/rice/Data_Type.ipp +14 -5
  15. data/rice/Data_Type_defn.hpp +28 -1
  16. data/rice/Director.cpp +0 -6
  17. data/rice/Director.hpp +0 -8
  18. data/rice/Hash.hpp +1 -1
  19. data/rice/Makefile.am +2 -12
  20. data/rice/Makefile.in +111 -88
  21. data/rice/Object.cpp +8 -1
  22. data/rice/Object.ipp +1 -1
  23. data/rice/Object_defn.hpp +8 -0
  24. data/rice/config.hpp +3 -0
  25. data/rice/config.hpp.in +3 -0
  26. data/rice/detail/Auto_Function_Wrapper.ipp +1025 -512
  27. data/rice/detail/Auto_Member_Function_Wrapper.ipp +545 -272
  28. data/rice/detail/cfp.hpp +24 -0
  29. data/rice/detail/cfp.ipp +51 -0
  30. data/rice/detail/method_data.cpp +107 -336
  31. data/rice/detail/node.hpp +13 -13
  32. data/rice/detail/ruby.hpp +4 -0
  33. data/rice/detail/rubysig.hpp +19 -19
  34. data/rice/detail/traits.hpp +43 -0
  35. data/rice/generate_code.rb +37 -16
  36. data/rice/protect.hpp +1 -1
  37. data/rice/protect.ipp +448 -192
  38. data/rice/to_from_ruby.ipp +4 -12
  39. data/rice/to_from_ruby_defn.hpp +2 -2
  40. data/ruby/Makefile.in +99 -32
  41. data/ruby/lib/Makefile.in +61 -21
  42. data/ruby/lib/mkmf-rice.rb.in +9 -2
  43. data/ruby/lib/version.rb +1 -1
  44. data/sample/Makefile.in +33 -10
  45. data/test/Makefile.am +27 -0
  46. data/test/Makefile.in +270 -59
  47. data/test/ext/Makefile.am +43 -0
  48. data/test/ext/Makefile.in +399 -0
  49. data/test/ext/t1/Foo.hpp +10 -0
  50. data/test/ext/t1/extconf.rb +2 -0
  51. data/test/ext/t1/t1.cpp +15 -0
  52. data/test/ext/t2/extconf.rb +2 -0
  53. data/test/ext/t2/t2.cpp +11 -0
  54. data/test/test_Allocation_Strategies.cpp +1 -1
  55. data/test/test_Class.cpp +79 -0
  56. data/test/test_Data_Type.cpp +2 -2
  57. data/test/test_Director.cpp +114 -38
  58. data/test/test_Module.cpp +27 -2
  59. data/test/test_To_From_Ruby.cpp +4 -4
  60. data/test/test_rice.rb +9 -1
  61. metadata +23 -8
  62. data/rice/detail/method_data.cpp.rpp +0 -301
  63. data/rice/detail/mininode.cpp.rpp +0 -62
  64. data/rice/detail/mininode.hpp.rpp +0 -119
  65. data/rice/detail/remove_const.hpp +0 -21
@@ -0,0 +1,24 @@
1
+ #ifndef Rice__detail__cfp__hpp_
2
+ #define Rice__detail__cfp__hpp_
3
+
4
+ #include "ruby.hpp"
5
+
6
+ namespace Rice
7
+ {
8
+
9
+ namespace detail
10
+ {
11
+
12
+ VALUE * cfp();
13
+
14
+ VALUE & cfp_data_memo_node_and_pc(VALUE * cfp);
15
+ VALUE & cfp_self(VALUE * cfp);
16
+ VALUE & cfp_method_class(VALUE * cfp);
17
+
18
+ } // detail
19
+
20
+ } // Rice
21
+
22
+ #include "cfp.ipp"
23
+
24
+ #endif // Rice__detail__cfp__hpp_
@@ -0,0 +1,51 @@
1
+ namespace detail
2
+ {
3
+
4
+ struct rb_thread_struct
5
+ {
6
+ VALUE self;
7
+ void *vm;
8
+ VALUE *stack;
9
+ unsigned long stack_size;
10
+ VALUE *cfp;
11
+ /* ... */
12
+ };
13
+
14
+ typedef struct rb_thread_struct rb_thread_t;
15
+
16
+ } // namespace detail
17
+
18
+ extern "C" detail::rb_thread_t * ruby_current_thread;
19
+
20
+ inline
21
+ VALUE *
22
+ Rice::detail::
23
+ cfp()
24
+ {
25
+ return ruby_current_thread->cfp;
26
+ }
27
+
28
+ inline
29
+ VALUE &
30
+ Rice::detail::
31
+ cfp_data_memo_node_and_pc(VALUE * cfp)
32
+ {
33
+ return cfp[0];
34
+ }
35
+
36
+ inline
37
+ VALUE &
38
+ Rice::detail::
39
+ cfp_self(VALUE * cfp)
40
+ {
41
+ return cfp[5];
42
+ }
43
+
44
+ inline
45
+ VALUE &
46
+ Rice::detail::
47
+ cfp_method_class(VALUE * cfp)
48
+ {
49
+ return cfp[11];
50
+ }
51
+
@@ -1,392 +1,163 @@
1
1
  #include "method_data.hpp"
2
+ #include "ruby.hpp"
2
3
 
3
4
  // TODO: This is silly, autoconf...
4
5
  #undef PACKAGE_NAME
5
6
  #undef PACKAGE_STRING
6
7
  #undef PACKAGE_TARNAME
7
8
  #undef PACKAGE_VERSION
8
-
9
9
  #include "../config.hpp"
10
10
 
11
-
12
- #if defined(HAVE_NODE_H)
11
+ #ifndef RUBY_VM
13
12
  /* pre-YARV */
14
13
  #include <node.h>
15
- #elif defined(REALLY_HAVE_RUBY_NODE_H)
16
- /* YARV */
17
- #include <ruby/node.h>
18
- #else
19
- /* YARV without node.h */
20
- #include "mininode.hpp"
21
- using namespace Rice::detail::Mininode;
22
- #endif
23
-
24
14
  #include "env.hpp"
15
+ #endif
25
16
 
26
- #ifdef RUBY_VM
27
-
28
- /* YARV */
17
+ /* 1.8.6 compatibility */
18
+ #ifndef RCLASS_M_TBL
19
+ #define RCLASS_M_TBL(x) (RCLASS(x)->m_tbl)
20
+ #endif
29
21
 
30
22
  namespace
31
23
  {
32
24
 
33
- struct rb_thread_struct
34
- {
35
- VALUE self;
36
- void *vm;
37
- VALUE *stack;
38
- unsigned long stack_size;
39
- VALUE *cfp;
40
- /* ... */
41
- };
42
-
43
- typedef struct rb_thread_struct rb_thread_t;
25
+ VALUE DATA_MAGIC = rb_fix_new(0xDA7A);
44
26
 
45
27
  } // namespace
46
28
 
47
- extern "C" rb_thread_t * ruby_current_thread;
48
-
49
- #endif
50
-
51
- namespace
52
- {
53
-
54
29
  #ifdef RUBY_VM
55
30
 
56
- /* YARV */
57
-
58
- #define CFP_DATA_MEMO_NODE_AND_PC cfp[0]
59
- #define CFP_METHOD_CLASS cfp[11]
60
-
61
- /* On YARV, we store the method data on the stack. We don't have to pop
62
- * it off the stack, because the stack pointer will be reset to the
63
- * previous frame's stack pointer when the function returns.
64
- */
65
- static void fix_frame()
31
+ VALUE
32
+ Rice::detail::
33
+ method_data()
66
34
  {
67
- do {
68
- VALUE * cfp = ruby_current_thread->cfp;
69
- CFP_DATA_MEMO_NODE_AND_PC = RBASIC(CFP_METHOD_CLASS)->klass;
35
+ ID id;
36
+ VALUE origin;
37
+ if (!rb_frame_method_id_and_class(&id, &origin))
38
+ {
39
+ rb_raise(
40
+ rb_eRuntimeError,
41
+ "Cannot get method id and class for function");
42
+ }
70
43
 
71
- if(rb_type(CFP_DATA_MEMO_NODE_AND_PC) != T_NODE)
72
- {
73
- /* This can happen for module functions that are created after
74
- * the stub function */
75
- rb_raise(
76
- rb_eRuntimeError,
77
- "Cannot find method data for module function");
78
- }
79
- else
80
- {
81
- CFP_METHOD_CLASS = RCLASS_SUPER(CFP_METHOD_CLASS);
82
- }
83
- } while(0);
84
- }
44
+ VALUE memo = rb_ivar_get(origin, 0);
85
45
 
86
- #define FIX_FRAME() \
87
- fix_frame()
46
+ if(rb_type(memo) != T_ARRAY && RARRAY_PTR(memo)[0] != DATA_MAGIC)
47
+ {
48
+ /* This can happen for module functions that are created after
49
+ * the stub function */
50
+ rb_raise(
51
+ rb_eRuntimeError,
52
+ "Cannot find method data for module function");
53
+ }
88
54
 
89
- static NODE * data_memo_node()
90
- {
91
- VALUE * cfp = ruby_current_thread->cfp;
92
- return (NODE *)CFP_DATA_MEMO_NODE_AND_PC;
55
+ return RARRAY_PTR(memo)[1];
93
56
  }
94
57
 
95
58
  #else
96
59
 
97
60
  /* pre-YARV */
98
61
 
99
- /* Okay to not pop this temporary frame, since it will be popped by the
100
- * caller
101
- */
102
- #define FIX_FRAME() \
103
- struct FRAME _frame = *ruby_frame; \
104
- _frame.last_class = RCLASS(ruby_frame->last_class)->super; \
105
- _frame.prev = ruby_frame; \
106
- ruby_frame = &_frame; \
107
-
108
- static NODE * data_memo_node()
62
+ VALUE
63
+ Rice::detail::
64
+ method_data()
109
65
  {
110
- return (NODE *)(RBASIC(ruby_frame->prev->last_class)->klass);
66
+ VALUE origin = ruby_frame->last_class;
67
+ VALUE memo = rb_ivar_get(origin, 0);
68
+ return RARRAY_PTR(memo)[1];
111
69
  }
112
70
 
113
71
  #endif
114
72
 
115
- typedef VALUE (*Method_Func)(ANYARGS);
116
-
117
- static Method_Func actual_cfunc()
118
- {
119
- return data_memo_node()->nd_cfnc;
120
- }
121
-
122
- static VALUE data_wrapper_m1(int argc, VALUE * argv, VALUE self)
123
- {
124
- VALUE result;
125
- FIX_FRAME();
126
- result = (*actual_cfunc())(argc, argv, self);
127
- return result;
128
- }
129
-
130
- static VALUE data_wrapper_0(VALUE self)
131
- {
132
- VALUE result;
133
- FIX_FRAME();
134
- result = (*actual_cfunc())(self);
135
- return result;
136
- }
137
-
138
- static VALUE data_wrapper_1(VALUE self, VALUE arg1)
139
- {
140
- VALUE result;
141
- FIX_FRAME();
142
- result = (*actual_cfunc())(self, arg1);
143
- return result;
144
- }
145
- static VALUE data_wrapper_2(VALUE self, VALUE arg1, VALUE arg2)
146
- {
147
- VALUE result;
148
- FIX_FRAME();
149
- result = (*actual_cfunc())(self, arg1, arg2);
150
- return result;
151
- }
152
- static VALUE data_wrapper_3(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3)
153
- {
154
- VALUE result;
155
- FIX_FRAME();
156
- result = (*actual_cfunc())(self, arg1, arg2, arg3);
157
- return result;
158
- }
159
- static VALUE data_wrapper_4(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4)
160
- {
161
- VALUE result;
162
- FIX_FRAME();
163
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4);
164
- return result;
165
- }
166
- static VALUE data_wrapper_5(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5)
167
- {
168
- VALUE result;
169
- FIX_FRAME();
170
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5);
171
- return result;
172
- }
173
- static VALUE data_wrapper_6(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6)
174
- {
175
- VALUE result;
176
- FIX_FRAME();
177
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6);
178
- return result;
179
- }
180
- static VALUE data_wrapper_7(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7)
181
- {
182
- VALUE result;
183
- FIX_FRAME();
184
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
185
- return result;
186
- }
187
- static VALUE data_wrapper_8(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8)
188
- {
189
- VALUE result;
190
- FIX_FRAME();
191
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
192
- return result;
193
- }
194
- static VALUE data_wrapper_9(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9)
195
- {
196
- VALUE result;
197
- FIX_FRAME();
198
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
199
- return result;
200
- }
201
- static VALUE data_wrapper_10(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10)
202
- {
203
- VALUE result;
204
- FIX_FRAME();
205
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
206
- return result;
207
- }
208
- static VALUE data_wrapper_11(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10, VALUE arg11)
209
- {
210
- VALUE result;
211
- FIX_FRAME();
212
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
213
- return result;
214
- }
215
- static VALUE data_wrapper_12(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10, VALUE arg11, VALUE arg12)
216
- {
217
- VALUE result;
218
- FIX_FRAME();
219
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
220
- return result;
221
- }
222
- static VALUE data_wrapper_13(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10, VALUE arg11, VALUE arg12, VALUE arg13)
223
- {
224
- VALUE result;
225
- FIX_FRAME();
226
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
227
- return result;
228
- }
229
- static VALUE data_wrapper_14(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10, VALUE arg11, VALUE arg12, VALUE arg13, VALUE arg14)
230
- {
231
- VALUE result;
232
- FIX_FRAME();
233
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
234
- return result;
235
- }
236
- static VALUE data_wrapper_15(VALUE self, VALUE arg1, VALUE arg2, VALUE arg3, VALUE arg4, VALUE arg5, VALUE arg6, VALUE arg7, VALUE arg8, VALUE arg9, VALUE arg10, VALUE arg11, VALUE arg12, VALUE arg13, VALUE arg14, VALUE arg15)
237
- {
238
- VALUE result;
239
- FIX_FRAME();
240
- result = (*actual_cfunc())(self, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
241
- return result;
242
- }
243
-
244
- } // namespace
245
-
246
- /* Define a method and attach data to it.
247
- *
248
- * The method looks to ruby like a normal aliased CFUNC, with a modified
249
- * origin class:
250
- *
251
- * NODE_FBODY
252
- * |- (u1) orig - origin class
253
- * | |- basic
254
- * | | |- flags - origin class flags + FL_SINGLETON
255
- * | | +- klass - NODE_MEMO
256
- * | | |- (u1) cfnc - actual C function to call
257
- * | | |- (u2) rval - stored data
258
- * | | +- (u3) 0
259
- * | |- iv_tbl - 0
260
- * | |- m_tbl - 0
261
- * | +- super - actual origin class
262
- * |- (u2) mid - name of the method
263
- * +- (u3) head - NODE_CFUNC
264
- * |- (u1) cfnc - wrapper function to call
265
- * +- (u2) argc - function arity
266
- *
267
- * Or, on YARV:
268
- *
269
- * NODE_FBODY
270
- * |- (u1) oid - name of the method
271
- * +- (u2) body - NODE_METHOD
272
- * |- (u1) clss - origin class
273
- * | |- basic
274
- * | | |- flags - origin class flags + FL_SINGLETON
275
- * | | +- klass - NODE_MEMO
276
- * | | |- (u1) cfnc - actual C function to call
277
- * | | |- (u2) rval - stored data
278
- * | | +- (u3) 0
279
- * | |- ptr - rb_classext_t
280
- * | | |- super - actual origin class
281
- * | | +- iv_tbl - 0
282
- * | |- m_tbl - 0
283
- * | +- iv_index_tbl - 0?
284
- * |- (u2) body - NODE_CFUNC
285
- * | |- (u1) cfnc - wrapper function to call
286
- * | |- (u2) argc - function arity
287
- * +- (u3) noex - NOEX_PUBLIC
288
- *
289
- * When the wrapper function is called, last_class is set to the origin
290
- * class found in the FBODY node. So that the method data will be
291
- * accessible, and so last_class will point to klass and not to our MEMO
292
- * node, it is necessary to "fix" the current frame.
293
- *
294
- * Pre-YARV, this means we duplicate the current frame and set last_class:
295
- *
296
- * ruby_frame
297
- * |- last_class - klass
298
- * |- prev
299
- * | |- last_class - NODE_MEMO
300
- * | | |- (u1) cfnc - actual C function to call
301
- * | | |- (u2) rval - stored data
302
- * | | +- (u3) 0
303
- * | |- prev - the real previous frame
304
- * | +- ...
305
- * +- ...
306
- *
307
- * The method data is then accessible via
308
- * ruby_frame->prev->last_class->rval.
309
- *
310
- * On YARV, the current frame is not duplicated; rather, the method data
311
- * is placed on the stack and is referenced by one of the unused members
312
- * of the control frame (the program counter):
313
- *
314
- * ruby_current_thread->cfp
315
- * |- pc - NODE_MEMO
316
- * | |- (u1) cfnc - actual C function to call
317
- * | |- (u2) rval - stored data
318
- * | +- (u3) 0
319
- * |- method_class - klass
320
- * +- ...
321
- *
322
- */
73
+ // Define a method and attach data to it.
74
+ // The method looks to ruby like a normal aliased CFUNC, with a modified
75
+ // origin class.
76
+ //
77
+ // How this works:
78
+ //
79
+ // To store method data and have it registered with the GC, we need a
80
+ // "slot" to put it in. This "slot" must be recognized and marked by
81
+ // the garbage collector. There happens to be such a place we can put
82
+ // data, and it has to do with aliased methods. When Ruby creates an
83
+ // alias for a method, it stores a reference to the original class in
84
+ // the method entry. The form of the method entry differs from ruby
85
+ // version to ruby version, but the concept is the same across all of
86
+ // them.
87
+ //
88
+ // In Rice, we make use of this by defining a method on a dummy class,
89
+ // then attaching that method to our real class. The method is a real
90
+ // method in our class, but its origin class is our dummy class.
91
+ //
92
+ // When Ruby makes a method call, it stores the origin class in the
93
+ // current stack frame. When Ruby calls into Rice, we grab the origin
94
+ // class from the stack frame, then pull the data out of the origin
95
+ // class. The data item is then used to determine how to convert
96
+ // arguments and return type, how to handle exceptions, etc.
97
+ //
98
+ // It used to be the case that Rice would "fix" the call frame so that
99
+ // the modified origin class was not visible to the called function (it
100
+ // would appear to the callee that the origin class was the same as the
101
+ // class it was defined on). However, this required modifying the call
102
+ // frame directly, and the layout of that frame varies from version to
103
+ // version. To keep things simple (and as a side effect improve
104
+ // performance), Rice no longer hides the modified origin class this way.
105
+ //
106
+ // Functions that make use of "last_class" (1.8) or
107
+ // "rb_frame_method_id_and_class" (1.9) will therefore not get the
108
+ // results they expect.
323
109
  VALUE
324
110
  Rice::detail::
325
111
  define_method_with_data(
326
112
  VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data)
327
113
  {
328
- /* TODO: origin should have #to_s and #inspect methods defined */
329
114
  #ifdef HAVE_RB_CLASS_BOOT
330
115
  VALUE origin = rb_class_boot(klass);
331
116
  #else
332
117
  VALUE origin = rb_class_new(klass);
333
118
  #endif
334
- NODE * node;
335
119
 
336
- VALUE (*data_wrapper)(ANYARGS);
337
- switch(arity)
338
- {
339
- case 0: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_0); break;
340
- case 1: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_1); break;
341
- case 2: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_2); break;
342
- case 3: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_3); break;
343
- case 4: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_4); break;
344
- case 5: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_5); break;
345
- case 6: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_6); break;
346
- case 7: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_7); break;
347
- case 8: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_8); break;
348
- case 9: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_9); break;
349
- case 10: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_10); break;
350
- case 11: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_11); break;
351
- case 12: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_12); break;
352
- case 13: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_13); break;
353
- case 14: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_14); break;
354
- case 15: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_15); break;
355
- case -1: data_wrapper = RUBY_METHOD_FUNC(data_wrapper_m1); break;
356
- default: rb_raise(rb_eArgError, "unsupported arity %d", arity);
357
- }
120
+ // Create the memo object with a magic number so we can detect if
121
+ // we're getting the origin class we expect (this can happen if the
122
+ // module_function method is called on a Rice function on ruby 1.9).
123
+ VALUE memo = rb_assoc_new(DATA_MAGIC, data);
358
124
 
125
+ // Set the class name of our modified origin class to something
126
+ // obvious in case someone tries to inspect it.
127
+ VALUE real_class_name = rb_class_name(klass);
128
+ VALUE origin_class_name = rb_str_plus(
129
+ real_class_name,
130
+ rb_str_new2("<data wrapper>"));
131
+
132
+ // Create the modified origin class
359
133
  FL_SET(origin, FL_SINGLETON);
360
134
  rb_singleton_class_attached(origin, klass);
361
- rb_name_class(origin, SYM2ID(rb_class_name(klass)));
135
+ rb_name_class(origin, SYM2ID(rb_str_intern(origin_class_name)));
136
+
137
+ // Attach our "memo" to the origin class
138
+ rb_ivar_set(origin, 0, memo);
139
+
140
+ // Create the aliased method on the origin class
141
+ rb_define_method(
142
+ origin,
143
+ rb_id2name(id),
144
+ cfunc,
145
+ arity);
146
+
147
+ // Alias the method in the origin class so we can copy it to another
148
+ // class with the origin class intact as part of the method entry
149
+ rb_alias(
150
+ origin,
151
+ rb_intern("dummy"),
152
+ id);
362
153
 
363
- RBASIC(origin)->klass = (VALUE)NEW_NODE(NODE_MEMO, cfunc, data, 0);
154
+ // Copy the method entry to the real class
155
+ st_data_t dummy_entry;
156
+ st_lookup(RCLASS_M_TBL(origin), rb_intern("dummy"), &dummy_entry);
157
+ st_insert(RCLASS_M_TBL(klass), id, dummy_entry);
364
158
 
365
- #ifdef RUBY_VM
366
- /* YARV */
367
- node = NEW_FBODY(
368
- NEW_METHOD(
369
- NEW_CFUNC(data_wrapper, arity),
370
- origin,
371
- NOEX_PUBLIC),
372
- id);
373
- st_insert(RCLASS_M_TBL(klass), id, (st_data_t)node);
374
- #else
375
- /* pre-YARV */
376
- node = NEW_FBODY(
377
- NEW_CFUNC(data_wrapper, arity),
378
- id,
379
- origin);
380
- rb_add_method(klass, id, node, NOEX_PUBLIC);
381
- #endif
159
+ // Clear the table so we don't try to double-free the method entry
160
+ RCLASS_M_TBL(origin) = st_init_numtable();
382
161
 
383
162
  return Qnil;
384
163
  }
385
-
386
- VALUE
387
- Rice::detail::
388
- method_data()
389
- {
390
- return data_memo_node()->nd_rval;
391
- }
392
-