rice 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Doxyfile +1 -1
- data/Makefile.in +130 -52
- data/README +45 -79
- data/Rakefile +1 -36
- data/aclocal.m4 +133 -61
- data/config.guess +43 -8
- data/config.sub +41 -13
- data/configure +1370 -1898
- data/configure.ac +2 -2
- data/doxygen.ac +1 -1
- data/extconf.rb +3 -1
- data/rice/Arg_impl.hpp +2 -2
- data/rice/Data_Type.cpp +34 -1
- data/rice/Data_Type.ipp +14 -5
- data/rice/Data_Type_defn.hpp +28 -1
- data/rice/Director.cpp +0 -6
- data/rice/Director.hpp +0 -8
- data/rice/Hash.hpp +1 -1
- data/rice/Makefile.am +2 -12
- data/rice/Makefile.in +111 -88
- data/rice/Object.cpp +8 -1
- data/rice/Object.ipp +1 -1
- data/rice/Object_defn.hpp +8 -0
- data/rice/config.hpp +3 -0
- data/rice/config.hpp.in +3 -0
- data/rice/detail/Auto_Function_Wrapper.ipp +1025 -512
- data/rice/detail/Auto_Member_Function_Wrapper.ipp +545 -272
- data/rice/detail/cfp.hpp +24 -0
- data/rice/detail/cfp.ipp +51 -0
- data/rice/detail/method_data.cpp +107 -336
- data/rice/detail/node.hpp +13 -13
- data/rice/detail/ruby.hpp +4 -0
- data/rice/detail/rubysig.hpp +19 -19
- data/rice/detail/traits.hpp +43 -0
- data/rice/generate_code.rb +37 -16
- data/rice/protect.hpp +1 -1
- data/rice/protect.ipp +448 -192
- data/rice/to_from_ruby.ipp +4 -12
- data/rice/to_from_ruby_defn.hpp +2 -2
- data/ruby/Makefile.in +99 -32
- data/ruby/lib/Makefile.in +61 -21
- data/ruby/lib/mkmf-rice.rb.in +9 -2
- data/ruby/lib/version.rb +1 -1
- data/sample/Makefile.in +33 -10
- data/test/Makefile.am +27 -0
- data/test/Makefile.in +270 -59
- data/test/ext/Makefile.am +43 -0
- data/test/ext/Makefile.in +399 -0
- data/test/ext/t1/Foo.hpp +10 -0
- data/test/ext/t1/extconf.rb +2 -0
- data/test/ext/t1/t1.cpp +15 -0
- data/test/ext/t2/extconf.rb +2 -0
- data/test/ext/t2/t2.cpp +11 -0
- data/test/test_Allocation_Strategies.cpp +1 -1
- data/test/test_Class.cpp +79 -0
- data/test/test_Data_Type.cpp +2 -2
- data/test/test_Director.cpp +114 -38
- data/test/test_Module.cpp +27 -2
- data/test/test_To_From_Ruby.cpp +4 -4
- data/test/test_rice.rb +9 -1
- metadata +23 -8
- data/rice/detail/method_data.cpp.rpp +0 -301
- data/rice/detail/mininode.cpp.rpp +0 -62
- data/rice/detail/mininode.hpp.rpp +0 -119
- data/rice/detail/remove_const.hpp +0 -21
data/rice/detail/cfp.hpp
ADDED
@@ -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_
|
data/rice/detail/cfp.ipp
ADDED
@@ -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
|
+
|
data/rice/detail/method_data.cpp
CHANGED
@@ -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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
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
|
-
|
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
|
-
|
100
|
-
|
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
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
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(
|
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
|
-
|
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
|
-
|
366
|
-
|
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
|
-
|