1313import java .util .Objects ;
1414import java .util .concurrent .ConcurrentHashMap ;
1515import java .util .concurrent .ConcurrentMap ;
16+ import java .util .function .BinaryOperator ;
1617
1718public final class LambdaFactory {
1819 private static final class LambdaClassLoader extends ClassLoader {
@@ -66,6 +67,291 @@ boolean generateBridge() {
6667 }
6768 }
6869
70+ private static final class LambdaTypeConverters {
71+ @ FunctionalInterface
72+ interface Operation {
73+ void run (final MethodVisitor visitor , final Type fromType , final Type toType );
74+ }
75+
76+ private static final class TypedOperation {
77+ private final int fromSort ;
78+ private final int toSort ;
79+ private final Operation operation ;
80+
81+ TypedOperation (final int fromSort , final int toSort , final Operation operation ) {
82+ this .fromSort = fromSort ;
83+ this .toSort = toSort ;
84+ this .operation = operation ;
85+ }
86+
87+ int from () {
88+ return this .fromSort ;
89+ }
90+
91+ int to () {
92+ return this .toSort ;
93+ }
94+
95+ Operation op () {
96+ return this .operation ;
97+ }
98+ }
99+
100+ private static final Operation [][] OPERATIONS = build (
101+ conv (Type .VOID , Type .VOID , nop ()),
102+ conv (Type .VOID , Type .BOOLEAN , load (Opcodes .ICONST_0 )),
103+ conv (Type .VOID , Type .CHAR , load (Opcodes .ICONST_0 )),
104+ conv (Type .VOID , Type .BYTE , load (Opcodes .ICONST_0 )),
105+ conv (Type .VOID , Type .SHORT , load (Opcodes .ICONST_0 )),
106+ conv (Type .VOID , Type .INT , load (Opcodes .ICONST_0 )),
107+ conv (Type .VOID , Type .FLOAT , load (Opcodes .FCONST_0 )),
108+ conv (Type .VOID , Type .LONG , load (Opcodes .LCONST_0 )),
109+ conv (Type .VOID , Type .DOUBLE , load (Opcodes .DCONST_0 )),
110+ conv (Type .VOID , Type .ARRAY , load (Opcodes .ACONST_NULL )),
111+ conv (Type .VOID , Type .OBJECT , load (Opcodes .ACONST_NULL )),
112+ conv (Type .VOID , Type .METHOD , nonsense ()),
113+
114+ conv (Type .BOOLEAN , Type .VOID , pop ()),
115+ conv (Type .BOOLEAN , Type .BOOLEAN , nop ()),
116+ conv (Type .BOOLEAN , Type .CHAR , nop ()),
117+ conv (Type .BOOLEAN , Type .BYTE , nop ()),
118+ conv (Type .BOOLEAN , Type .SHORT , nop ()),
119+ conv (Type .BOOLEAN , Type .INT , nop ()),
120+ conv (Type .BOOLEAN , Type .FLOAT , widen (Opcodes .I2F )),
121+ conv (Type .BOOLEAN , Type .LONG , widen (Opcodes .I2L )),
122+ conv (Type .BOOLEAN , Type .DOUBLE , widen (Opcodes .I2D )),
123+ conv (Type .BOOLEAN , Type .ARRAY , nonsense ()),
124+ conv (Type .BOOLEAN , Type .OBJECT , all (box (Boolean .class , "valueOf" ), cast (toType ()))),
125+ conv (Type .BOOLEAN , Type .METHOD , nonsense ()),
126+
127+ conv (Type .CHAR , Type .VOID , pop ()),
128+ conv (Type .CHAR , Type .BOOLEAN , all (load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
129+ conv (Type .CHAR , Type .CHAR , nop ()),
130+ conv (Type .CHAR , Type .BYTE , narrow (Opcodes .I2B )),
131+ conv (Type .CHAR , Type .SHORT , nop ()),
132+ conv (Type .CHAR , Type .INT , nop ()),
133+ conv (Type .CHAR , Type .FLOAT , widen (Opcodes .I2F )),
134+ conv (Type .CHAR , Type .LONG , widen (Opcodes .I2L )),
135+ conv (Type .CHAR , Type .DOUBLE , widen (Opcodes .I2D )),
136+ conv (Type .CHAR , Type .ARRAY , nonsense ()),
137+ conv (Type .CHAR , Type .OBJECT , all (box (Character .class , "valueOf" ), cast (toType ()))),
138+ conv (Type .CHAR , Type .METHOD , nonsense ()),
139+
140+ conv (Type .BYTE , Type .VOID , pop ()),
141+ conv (Type .BYTE , Type .BOOLEAN , all (load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
142+ conv (Type .BYTE , Type .CHAR , nop ()),
143+ conv (Type .BYTE , Type .BYTE , nop ()),
144+ conv (Type .BYTE , Type .SHORT , nop ()),
145+ conv (Type .BYTE , Type .INT , nop ()),
146+ conv (Type .BYTE , Type .FLOAT , widen (Opcodes .I2F )),
147+ conv (Type .BYTE , Type .LONG , widen (Opcodes .I2L )),
148+ conv (Type .BYTE , Type .DOUBLE , widen (Opcodes .I2D )),
149+ conv (Type .BYTE , Type .ARRAY , nonsense ()),
150+ conv (Type .BYTE , Type .OBJECT , all (box (Byte .class , "valueOf" ), cast (toType ()))),
151+ conv (Type .BYTE , Type .METHOD , nonsense ()),
152+
153+ conv (Type .SHORT , Type .VOID , pop ()),
154+ conv (Type .SHORT , Type .BOOLEAN , all (load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
155+ conv (Type .SHORT , Type .CHAR , nop ()),
156+ conv (Type .SHORT , Type .BYTE , narrow (Opcodes .I2B )),
157+ conv (Type .SHORT , Type .SHORT , nop ()),
158+ conv (Type .SHORT , Type .INT , nop ()),
159+ conv (Type .SHORT , Type .FLOAT , widen (Opcodes .I2F )),
160+ conv (Type .SHORT , Type .LONG , widen (Opcodes .I2L )),
161+ conv (Type .SHORT , Type .DOUBLE , widen (Opcodes .I2D )),
162+ conv (Type .SHORT , Type .ARRAY , nonsense ()),
163+ conv (Type .SHORT , Type .OBJECT , all (box (Short .class , "valueOf" ), cast (toType ()))),
164+ conv (Type .SHORT , Type .METHOD , nonsense ()),
165+
166+ conv (Type .INT , Type .VOID , pop ()),
167+ conv (Type .INT , Type .BOOLEAN , all (load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
168+ conv (Type .INT , Type .CHAR , narrow (Opcodes .I2C )),
169+ conv (Type .INT , Type .BYTE , narrow (Opcodes .I2B )),
170+ conv (Type .INT , Type .SHORT , narrow (Opcodes .I2S )),
171+ conv (Type .INT , Type .INT , nop ()),
172+ conv (Type .INT , Type .FLOAT , widen (Opcodes .I2F )),
173+ conv (Type .INT , Type .LONG , widen (Opcodes .I2L )),
174+ conv (Type .INT , Type .DOUBLE , widen (Opcodes .I2D )),
175+ conv (Type .INT , Type .ARRAY , nonsense ()),
176+ conv (Type .INT , Type .OBJECT , all (box (Integer .class , "valueOf" ), cast (toType ()))),
177+ conv (Type .INT , Type .METHOD , nonsense ()),
178+
179+ conv (Type .FLOAT , Type .VOID , pop ()),
180+ conv (Type .FLOAT , Type .BOOLEAN , all (narrow (Opcodes .F2I ), load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
181+ conv (Type .FLOAT , Type .CHAR , all (narrow (Opcodes .F2I ), narrow (Opcodes .I2C ))),
182+ conv (Type .FLOAT , Type .BYTE , all (narrow (Opcodes .F2I ), narrow (Opcodes .I2B ))),
183+ conv (Type .FLOAT , Type .SHORT , all (narrow (Opcodes .F2I ), narrow (Opcodes .I2S ))),
184+ conv (Type .FLOAT , Type .INT , narrow (Opcodes .F2I )),
185+ conv (Type .FLOAT , Type .FLOAT , nop ()),
186+ conv (Type .FLOAT , Type .LONG , narrow (Opcodes .F2L )),
187+ conv (Type .FLOAT , Type .DOUBLE , widen (Opcodes .F2D )),
188+ conv (Type .FLOAT , Type .ARRAY , nonsense ()),
189+ conv (Type .FLOAT , Type .OBJECT , all (box (Float .class , "valueOf" ), cast (toType ()))),
190+ conv (Type .FLOAT , Type .METHOD , nonsense ()),
191+
192+ conv (Type .LONG , Type .VOID , pop2 ()),
193+ conv (Type .LONG , Type .BOOLEAN , all (narrow (Opcodes .L2I ), load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
194+ conv (Type .LONG , Type .CHAR , all (narrow (Opcodes .L2I ), narrow (Opcodes .I2C ))),
195+ conv (Type .LONG , Type .BYTE , all (narrow (Opcodes .L2I ), narrow (Opcodes .I2B ))),
196+ conv (Type .LONG , Type .SHORT , all (narrow (Opcodes .L2I ), narrow (Opcodes .I2S ))),
197+ conv (Type .LONG , Type .INT , narrow (Opcodes .L2I )),
198+ conv (Type .LONG , Type .FLOAT , widen (Opcodes .L2F )),
199+ conv (Type .LONG , Type .LONG , nop ()),
200+ conv (Type .LONG , Type .DOUBLE , widen (Opcodes .L2D )),
201+ conv (Type .LONG , Type .ARRAY , nonsense ()),
202+ conv (Type .LONG , Type .OBJECT , all (box (Long .class , "valueOf" ), cast (toType ()))),
203+ conv (Type .LONG , Type .METHOD , nonsense ()),
204+
205+ conv (Type .DOUBLE , Type .VOID , pop2 ()),
206+ conv (Type .DOUBLE , Type .BOOLEAN , all (narrow (Opcodes .D2I ), load (Opcodes .ICONST_1 ), opcode (Opcodes .IAND ))),
207+ conv (Type .DOUBLE , Type .CHAR , all (narrow (Opcodes .D2I ), narrow (Opcodes .I2C ))),
208+ conv (Type .DOUBLE , Type .BYTE , all (narrow (Opcodes .D2I ), narrow (Opcodes .I2B ))),
209+ conv (Type .DOUBLE , Type .SHORT , all (narrow (Opcodes .D2I ), narrow (Opcodes .I2S ))),
210+ conv (Type .DOUBLE , Type .INT , narrow (Opcodes .D2I )),
211+ conv (Type .DOUBLE , Type .FLOAT , narrow (Opcodes .D2F )),
212+ conv (Type .DOUBLE , Type .LONG , narrow (Opcodes .D2L )),
213+ conv (Type .DOUBLE , Type .DOUBLE , nop ()),
214+ conv (Type .DOUBLE , Type .OBJECT , all (box (Double .class , "valueOf" ), cast (toType ()))),
215+ conv (Type .DOUBLE , Type .METHOD , nonsense ()),
216+
217+ conv (Type .ARRAY , Type .VOID , pop ()),
218+ conv (Type .ARRAY , Type .BOOLEAN , nonsense ()),
219+ conv (Type .ARRAY , Type .CHAR , nonsense ()),
220+ conv (Type .ARRAY , Type .BYTE , nonsense ()),
221+ conv (Type .ARRAY , Type .SHORT , nonsense ()),
222+ conv (Type .ARRAY , Type .INT , nonsense ()),
223+ conv (Type .ARRAY , Type .FLOAT , nonsense ()),
224+ conv (Type .ARRAY , Type .LONG , nonsense ()),
225+ conv (Type .ARRAY , Type .DOUBLE , nonsense ()),
226+ conv (Type .ARRAY , Type .OBJECT , cast (toType ())),
227+ conv (Type .ARRAY , Type .ARRAY , cast (toType ())),
228+ conv (Type .ARRAY , Type .METHOD , nonsense ()),
229+
230+ conv (Type .OBJECT , Type .VOID , pop ()),
231+ conv (Type .OBJECT , Type .BOOLEAN , all (cast (Boolean .class ), unbox (Boolean .class , "booleanValue" ))),
232+ conv (Type .OBJECT , Type .CHAR , all (cast (Character .class ), unbox (Character .class , "charValue" ))),
233+ conv (Type .OBJECT , Type .BYTE , all (cast (Number .class ), unbox (Number .class , "byteValue" ))),
234+ conv (Type .OBJECT , Type .SHORT , all (cast (Number .class ), unbox (Number .class , "shortValue" ))),
235+ conv (Type .OBJECT , Type .INT , all (cast (Number .class ), unbox (Number .class , "intValue" ))),
236+ conv (Type .OBJECT , Type .FLOAT , all (cast (Number .class ), unbox (Number .class , "floatValue" ))),
237+ conv (Type .OBJECT , Type .LONG , all (cast (Number .class ), unbox (Number .class , "longValue" ))),
238+ conv (Type .OBJECT , Type .DOUBLE , all (cast (Number .class ), unbox (Number .class , "doubleValue" ))),
239+ conv (Type .OBJECT , Type .OBJECT , cast (toType ())),
240+ conv (Type .OBJECT , Type .ARRAY , cast (toType ())),
241+ conv (Type .OBJECT , Type .METHOD , nonsense ()),
242+
243+ conv (Type .METHOD , Type .VOID , nonsense ()),
244+ conv (Type .METHOD , Type .BOOLEAN , nonsense ()),
245+ conv (Type .METHOD , Type .CHAR , nonsense ()),
246+ conv (Type .METHOD , Type .BYTE , nonsense ()),
247+ conv (Type .METHOD , Type .SHORT , nonsense ()),
248+ conv (Type .METHOD , Type .INT , nonsense ()),
249+ conv (Type .METHOD , Type .FLOAT , nonsense ()),
250+ conv (Type .METHOD , Type .LONG , nonsense ()),
251+ conv (Type .METHOD , Type .DOUBLE , nonsense ()),
252+ conv (Type .METHOD , Type .OBJECT , nonsense ()),
253+ conv (Type .METHOD , Type .ARRAY , nonsense ()),
254+ conv (Type .METHOD , Type .METHOD , nop ())
255+ );
256+
257+ private LambdaTypeConverters () {}
258+
259+ static void convert (final Type fromType , final Type toType , final MethodVisitor visitor ) {
260+ OPERATIONS [fromType .getSort ()][toType .getSort ()].run (visitor , fromType , toType );
261+ }
262+
263+ private static Operation [][] build (final TypedOperation ... ops ) {
264+ final Operation [][] operations = new Operation [12 ][12 ];
265+ for (final TypedOperation op : ops ) {
266+ operations [op .from ()][op .to ()] = op .op ();
267+ }
268+ return operations ;
269+ }
270+
271+ private static TypedOperation conv (final int from , final int to , final Operation operation ) {
272+ return new TypedOperation (from , to , operation );
273+ }
274+
275+ private static Operation nop () {
276+ return (visitor , fromType , toType ) -> {};
277+ }
278+
279+ private static Operation widen (final int opcode ) {
280+ return opcode (opcode );
281+ }
282+
283+ private static Operation narrow (final int opcode ) {
284+ return opcode (opcode );
285+ }
286+
287+ private static Operation load (final int opcode ) {
288+ return opcode (opcode );
289+ }
290+
291+ private static Operation pop () {
292+ return opcode (Opcodes .POP );
293+ }
294+
295+ private static Operation pop2 () {
296+ return opcode (Opcodes .POP2 );
297+ }
298+
299+ private static Operation opcode (final int opcode ) {
300+ return (visitor , fromType , toType ) -> visitor .visitInsn (opcode );
301+ }
302+
303+ private static Operation nonsense () {
304+ return (visitor , fromType , toType ) -> {
305+ throw new IllegalStateException ("Conversion between " + fromType + " to " + toType + " cannot be meaningfully carried out" );
306+ };
307+ }
308+
309+ private static Operation box (final Class <?> owner , @ SuppressWarnings ("SameParameterValue" ) final String name ) {
310+ return (visitor , fromType , toType ) -> visitor .visitMethodInsn (
311+ Opcodes .INVOKESTATIC ,
312+ Type .getInternalName (owner ),
313+ name ,
314+ Type .getMethodDescriptor (Type .getType (owner ), fromType ),
315+ owner .isInterface ()
316+ );
317+ }
318+
319+ private static Operation cast (final Class <?> target ) {
320+ return cast ((a , b ) -> Type .getType (target ));
321+ }
322+
323+ private static Operation cast (final BinaryOperator <Type > chooser ) {
324+ return (visitor , fromType , toType ) -> visitor .visitTypeInsn (Opcodes .CHECKCAST , chooser .apply (fromType , toType ).getInternalName ());
325+ }
326+
327+ @ SuppressWarnings ("unused" )
328+ private static BinaryOperator <Type > fromType () {
329+ return (a , b ) -> a ;
330+ }
331+
332+ private static BinaryOperator <Type > toType () {
333+ return (a , b ) -> b ;
334+ }
335+
336+ private static Operation unbox (final Class <?> owner , final String name ) {
337+ return (visitor , fromType , toType ) -> visitor .visitMethodInsn (
338+ owner .isInterface ()? Opcodes .INVOKEINTERFACE : Opcodes .INVOKEVIRTUAL ,
339+ Type .getInternalName (owner ),
340+ name ,
341+ Type .getMethodDescriptor (toType ),
342+ false
343+ );
344+ }
345+
346+ private static Operation all (final Operation ... ops ) {
347+ return (visitor , fromType , toType ) -> {
348+ for (final Operation op : ops ) {
349+ op .run (visitor , fromType , toType );
350+ }
351+ };
352+ }
353+ }
354+
69355 public interface LambdaMarker {}
70356
71357 @ Retention (RetentionPolicy .RUNTIME )
@@ -430,15 +716,8 @@ private static void generateInterfaceClassBridge(
430716 final Type bridgeType = Type .getType (bridgeInterfaceSignature .parameterType (i ));
431717 final Type targetType = Type .getType (interfaceSignature .parameterType (i ));
432718
433- if (bridgeType .getSort () == targetType .getSort ()) {
434- writer .visitVarInsn (bridgeType .getOpcode (Opcodes .ILOAD ), localIndex );
435-
436- if (bridgeType .getSort () == Type .OBJECT ) {
437- writer .visitTypeInsn (Opcodes .CHECKCAST , targetType .getInternalName ());
438- }
439- } else {
440- throw new UnsupportedOperationException ("Not yet implemented" );
441- }
719+ writer .visitVarInsn (bridgeType .getOpcode (Opcodes .ILOAD ), localIndex );
720+ LambdaTypeConverters .convert (bridgeType , targetType , writer );
442721
443722 localIndex += bridgeType .getSize ();
444723 }
@@ -448,15 +727,8 @@ private static void generateInterfaceClassBridge(
448727 final Type bridgeReturnType = Type .getType (bridgeInterfaceSignature .returnType ());
449728 final Type targetReturnType = Type .getType (interfaceSignature .returnType ());
450729
451- if (bridgeReturnType .getSort () == targetReturnType .getSort ()) {
452- if (targetReturnType .getSort () == Type .OBJECT ) {
453- writer .visitTypeInsn (Opcodes .CHECKCAST , bridgeReturnType .getInternalName ());
454- }
455-
456- writer .visitInsn (targetReturnType .getOpcode (Opcodes .IRETURN ));
457- } else {
458- throw new UnsupportedOperationException ("Not yet implemented" );
459- }
730+ LambdaTypeConverters .convert (targetReturnType , bridgeReturnType , writer );
731+ writer .visitInsn (bridgeReturnType .getOpcode (Opcodes .IRETURN ));
460732
461733 writer .visitMaxs (localIndex , localIndex );
462734 writer .visitEnd ();
0 commit comments