29
29
package org .jruby .internal .runtime .methods ;
30
30
31
31
import java .lang .invoke .MethodHandle ;
32
- import java .util .concurrent .Callable ;
32
+ import java .lang .invoke .MethodHandles ;
33
+ import java .util .function .Supplier ;
33
34
35
+ import com .headius .invokebinder .SmartBinder ;
34
36
import org .jruby .RubyModule ;
35
37
import org .jruby .runtime .Arity ;
36
38
import org .jruby .runtime .Block ;
40
42
import org .jruby .runtime .Visibility ;
41
43
import org .jruby .runtime .builtin .IRubyObject ;
42
44
45
+ import static org .jruby .runtime .Helpers .arrayOf ;
43
46
import static org .jruby .util .StringSupport .EMPTY_STRING_ARRAY ;
44
47
import static org .jruby .util .StringSupport .split ;
45
48
56
59
* @author headius
57
60
*/
58
61
public class HandleMethod extends DynamicMethod implements MethodArgs2 , Cloneable {
59
- private Callable <MethodHandle > maker0 ;
60
- private Callable <MethodHandle > maker1 ;
61
- private Callable <MethodHandle > maker2 ;
62
- private Callable <MethodHandle > maker3 ;
63
- private Callable <MethodHandle > maker4 ;
62
+ private Supplier <MethodHandle > maker0 ;
63
+ private Supplier <MethodHandle > maker1 ;
64
+ private Supplier <MethodHandle > maker2 ;
65
+ private Supplier <MethodHandle > maker3 ;
66
+ private Supplier <MethodHandle > maker4 ;
64
67
private MethodHandle target0 ;
65
68
private MethodHandle target1 ;
66
69
private MethodHandle target2 ;
@@ -74,6 +77,16 @@ public class HandleMethod extends DynamicMethod implements MethodArgs2, Cloneabl
74
77
private final boolean builtin ;
75
78
private final boolean notImplemented ;
76
79
80
+ private static final com .headius .invokebinder .Signature ARITY_0 =
81
+ com .headius .invokebinder .Signature .from (
82
+ IRubyObject .class ,
83
+ arrayOf (ThreadContext .class , IRubyObject .class , RubyModule .class , String .class , Block .class ),
84
+ "context" , "self" , "selfType" , "name" , "block" );
85
+ private static final com .headius .invokebinder .Signature ARITY_1 = ARITY_0 .insertArg (4 , "arg0" , IRubyObject .class );
86
+ private static final com .headius .invokebinder .Signature ARITY_2 = ARITY_1 .insertArg (5 , "arg1" , IRubyObject .class );
87
+ private static final com .headius .invokebinder .Signature ARITY_3 = ARITY_2 .insertArg (6 , "arg2" , IRubyObject .class );
88
+ private static final com .headius .invokebinder .Signature [] ARITIES = {ARITY_0 , ARITY_1 , ARITY_2 , ARITY_3 };
89
+
77
90
public HandleMethod (
78
91
RubyModule implementationClass ,
79
92
Visibility visibility ,
@@ -84,11 +97,11 @@ public HandleMethod(
84
97
String parameterDesc ,
85
98
final int min ,
86
99
final int max ,
87
- final Callable <MethodHandle > maker0 ,
88
- final Callable <MethodHandle > maker1 ,
89
- final Callable <MethodHandle > maker2 ,
90
- final Callable <MethodHandle > maker3 ,
91
- final Callable <MethodHandle > maker4 ) {
100
+ final Supplier <MethodHandle > maker0 ,
101
+ final Supplier <MethodHandle > maker1 ,
102
+ final Supplier <MethodHandle > maker2 ,
103
+ final Supplier <MethodHandle > maker3 ,
104
+ final Supplier <MethodHandle > maker4 ) {
92
105
93
106
super (implementationClass , visibility , name );
94
107
this .signature = Signature .decode (encodedSignature );
@@ -130,74 +143,118 @@ public boolean isNative() {
130
143
}
131
144
132
145
private MethodHandle ensureTarget0 () {
146
+ MethodHandle target0 ;
133
147
if (!initialized0 ) {
134
- this .target0 = safeCall (maker0 );
148
+ Supplier <MethodHandle > maker0 = this .maker0 ;
149
+ if (maker0 == null ) {
150
+ target0 = adaptSpecificToVarargs (ensureTarget4 (), 0 );
151
+ } else {
152
+ target0 = maker0 .get ();
153
+ }
154
+ this .target0 = target0 ;
155
+ this .maker0 = null ;
135
156
initialized0 = true ;
136
- maker0 = null ;
157
+ } else {
158
+ target0 = this .target0 ;
137
159
}
138
- return this . target0 ;
160
+ return target0 ;
139
161
}
140
162
141
163
private MethodHandle ensureTarget1 () {
164
+ MethodHandle target1 ;
142
165
if (!initialized1 ) {
143
- this .target1 = safeCall (maker1 );
166
+ Supplier <MethodHandle > maker1 = this .maker1 ;
167
+ if (maker1 == null ) {
168
+ target1 = adaptSpecificToVarargs (ensureTarget4 (), 1 );
169
+ } else {
170
+ target1 = maker1 .get ();
171
+ }
172
+ this .target1 = target1 ;
173
+ this .maker1 = null ;
144
174
initialized1 = true ;
145
- maker1 = null ;
175
+ } else {
176
+ target1 = this .target1 ;
146
177
}
147
- return this . target1 ;
178
+ return target1 ;
148
179
}
149
180
150
181
private MethodHandle ensureTarget2 () {
182
+ MethodHandle target2 ;
151
183
if (!initialized2 ) {
152
- this .target2 = safeCall (maker2 );
184
+ Supplier <MethodHandle > maker2 = this .maker2 ;
185
+ if (maker2 == null ) {
186
+ target2 = adaptSpecificToVarargs (ensureTarget4 (), 2 );
187
+ } else {
188
+ target2 = maker2 .get ();
189
+ }
190
+ this .target2 = target2 ;
191
+ this .maker2 = null ;
153
192
initialized2 = true ;
154
- maker2 = null ;
193
+ } else {
194
+ target2 = this .target2 ;
155
195
}
156
- return this . target2 ;
196
+ return target2 ;
157
197
}
158
198
159
199
private MethodHandle ensureTarget3 () {
200
+ MethodHandle target3 ;
160
201
if (!initialized3 ) {
161
- this .target3 = safeCall (maker3 );
202
+ Supplier <MethodHandle > maker3 = this .maker3 ;
203
+ if (maker3 == null ) {
204
+ target3 = adaptSpecificToVarargs (ensureTarget4 (), 3 );
205
+ } else {
206
+ target3 = maker3 .get ();
207
+ }
208
+ this .target3 = target3 ;
209
+ this .maker3 = null ;
162
210
initialized3 = true ;
163
- maker3 = null ;
211
+ } else {
212
+ target3 = this .target3 ;
164
213
}
165
- return this . target3 ;
214
+ return target3 ;
166
215
}
167
216
168
217
private MethodHandle ensureTarget4 () {
218
+ MethodHandle target4 ;
169
219
if (!initialized4 ) {
170
- this .target4 = safeCall (maker4 );
220
+ Supplier <MethodHandle > maker4 = this .maker4 ;
221
+ if (maker4 == null ) {
222
+ target4 = null ;
223
+ } else {
224
+ target4 = maker4 .get ();
225
+ }
226
+ this .target4 = target4 ;
171
227
initialized4 = true ;
172
- maker4 = null ;
228
+ this . maker4 = null ;
173
229
}
174
230
return this .target4 ;
175
231
}
176
232
177
- private static MethodHandle safeCall (Callable <MethodHandle > maker ) {
178
- try {
179
- if (maker == null ) return null ;
180
- return maker .call ();
181
- } catch (Exception e ) {
182
- Helpers .throwException (e );
183
- return null ;
233
+ private MethodHandle adaptSpecificToVarargs (MethodHandle varargs , int arity ) {
234
+ if (arity == 0 ) {
235
+ return MethodHandles .insertArguments (varargs , 4 , new Object [] {IRubyObject .NULL_ARRAY });
184
236
}
237
+
238
+ return SmartBinder .from (ARITIES [arity ])
239
+ .permute ("context" , "self" , "type" , "name" , "block" , "arg.*" )
240
+ .collect ("args" , "arg.*" )
241
+ .permute ("context" , "self" , "type" , "name" , "args" , "block" )
242
+ .invoke (varargs ).handle ();
185
243
}
186
244
187
245
@ Override
188
246
public IRubyObject call (ThreadContext context , IRubyObject self , RubyModule clazz , String name , IRubyObject [] args , Block block ) {
189
247
try {
190
248
MethodHandle target4 = ensureTarget4 ();
191
249
if (target4 != null ) {
192
- Arity .checkArgumentCount (context , args .length , min , max );
193
250
return (IRubyObject ) target4 .invokeExact (context , self , clazz , name , args , block );
194
251
} else {
195
252
int arity = Arity .checkArgumentCount (context , args .length , min , max );
196
253
switch (args .length ) {
197
- case 0 : return ( IRubyObject ) ensureTarget0 (). invokeExact (context , self , clazz , name , block );
198
- case 1 : return ( IRubyObject ) ensureTarget1 (). invokeExact (context , self , clazz , name , args [0 ], block );
199
- case 2 : return ( IRubyObject ) ensureTarget2 (). invokeExact (context , self , clazz , name , args [0 ], args [1 ], block );
200
- case 3 : return ( IRubyObject ) ensureTarget3 (). invokeExact (context , self , clazz , name , args [0 ], args [1 ], args [2 ], block );
254
+ case 0 : return call (context , self , clazz , name , block );
255
+ case 1 : return call (context , self , clazz , name , args [0 ], block );
256
+ case 2 : return call (context , self , clazz , name , args [0 ], args [1 ], block );
257
+ case 3 : return call (context , self , clazz , name , args [0 ], args [1 ], args [2 ], block );
201
258
default :
202
259
throw new RuntimeException ("invalid arity for call: " + arity );
203
260
}
0 commit comments