If targetClass is FI and has an adaptable functional method Find fn invoker method matching adaptable method of FI Emit bytecode for (expr is emitted): if(expr instanceof IFn && !(expr instanceof FI)) invokeDynamic(targetMethod, fnInvokerImplMethod) Else emit nothing
(ObjExpr objx, GeneratorAdapter gen, Expr expr, Class targetClass)
| 1691 | * Else emit nothing |
| 1692 | */ |
| 1693 | static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, Class targetClass) { |
| 1694 | // Optimization: |
| 1695 | // if(expr instanceof QualifiedMethodExpr) |
| 1696 | // emitInvokeDynamic(targetMethod, QME method) // DON'T emit expr |
| 1697 | |
| 1698 | java.lang.reflect.Method targetMethod = maybeFIMethod(targetClass); |
| 1699 | if (targetMethod == null) |
| 1700 | return false; |
| 1701 | |
| 1702 | // compute fn invoker method |
| 1703 | int paramCount = targetMethod.getParameterCount(); |
| 1704 | Class[] invokerParams = new Class[paramCount + 1]; |
| 1705 | invokerParams[0] = IFn.class; // close over Ifn as first arg |
| 1706 | StringBuilder invokeMethodBuilder = new StringBuilder("invoke"); |
| 1707 | for (int i = 0; i < paramCount; i++) { |
| 1708 | // FnInvokers only has prims for first 2 args |
| 1709 | invokerParams[i + 1] = paramCount <= 2 ? toInvokerParamType(targetMethod.getParameterTypes()[i]) : Object.class; |
| 1710 | invokeMethodBuilder.append(FnInvokers.encodeInvokerType(invokerParams[i + 1])); |
| 1711 | } |
| 1712 | // FnInvokers has prim returns for <= 2 params, only Object for higher |
| 1713 | Class retType = targetMethod.getReturnType(); |
| 1714 | char invokerReturnCode = FnInvokers.encodeInvokerType(paramCount <= 2 ? retType : Object.class); |
| 1715 | invokeMethodBuilder.append(invokerReturnCode); |
| 1716 | String invokerMethodName = invokeMethodBuilder.toString(); |
| 1717 | |
| 1718 | // Emit adapter to fn invoker method |
| 1719 | Type samType = Type.getType(targetClass); |
| 1720 | Type ifnType = Type.getType(IFn.class); |
| 1721 | try { |
| 1722 | java.lang.reflect.Method fnInvokerMethod = FnInvokers.class.getMethod(invokerMethodName, invokerParams); |
| 1723 | |
| 1724 | // if not (expr instanceof IFn), go to end label |
| 1725 | expr.emit(C.EXPRESSION, objx, gen); |
| 1726 | gen.dup(); |
| 1727 | gen.instanceOf(ifnType); |
| 1728 | Label endLabel = gen.newLabel(); |
| 1729 | gen.ifZCmp(Opcodes.IFEQ, endLabel); |
| 1730 | |
| 1731 | // if (expr instanceof FI), go to end label |
| 1732 | gen.dup(); |
| 1733 | gen.instanceOf(samType); |
| 1734 | gen.ifZCmp(Opcodes.IFNE, endLabel); |
| 1735 | |
| 1736 | // else adapt fn invoker method as impl for target method |
| 1737 | emitInvokeDynamicAdapter(gen, targetClass, targetMethod, FnInvokers.class, fnInvokerMethod); |
| 1738 | |
| 1739 | // end - checkcast that we have the target FI type |
| 1740 | gen.mark(endLabel); |
| 1741 | gen.checkCast(samType); |
| 1742 | return true; |
| 1743 | } catch (NoSuchMethodException e) { |
| 1744 | throw Util.sneakyThrow(e); // should never happen |
| 1745 | } |
| 1746 | |
| 1747 | } |
| 1748 | |
| 1749 | // LambdaMetafactory.metafactory() method handle for lambda bootstrap |
| 1750 | private static final Handle LMF_HANDLE = |
no test coverage detected