Skip to content

Commit 0758f0f

Browse files
committed
Add support for all type conversions
Signed-off-by: TheSilkMiner <thesilkminer@outlook.com>
1 parent 91167ca commit 0758f0f

File tree

1 file changed

+290
-18
lines changed

1 file changed

+290
-18
lines changed

JavaRuntime/src/main/java/org/openzen/zenscript/javart/factory/LambdaFactory.java

Lines changed: 290 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.Objects;
1414
import java.util.concurrent.ConcurrentHashMap;
1515
import java.util.concurrent.ConcurrentMap;
16+
import java.util.function.BinaryOperator;
1617

1718
public 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

Comments
 (0)