|
134 | 134 | import org.eclipse.jdt.core.dom.WhileStatement; |
135 | 135 | import org.eclipse.jdt.core.dom.WildcardType; |
136 | 136 |
|
| 137 | +// BH 2019.09.07 adds optimization for lambda methods that do not have finals |
137 | 138 | // BH 2019.08.29 fix for boxing of binary representation 0b01... (Google Closure Compiler bug) |
138 | 139 | // BH 2019.05.13 fix for Math.getExponent, ulp, nextDown, nextUp, nextAfter needing qualification |
139 | 140 | // BH 2019.05.13 fix for Function reference in new Foo()::test(...) |
@@ -163,6 +164,12 @@ public class Java2ScriptVisitor extends ASTVisitor { |
163 | 164 | */ |
164 | 165 | private static final boolean ALLOW_NEW_LAMBDA = false; |
165 | 166 |
|
| 167 | + /** |
| 168 | + * If there are no finals for a lambda method, then we can reuse the object. |
| 169 | + * This can be huge for preventing repetitive object creation |
| 170 | + */ |
| 171 | + private static final boolean ALLOW_LAMBDA_OBJECT_REUSE = true; |
| 172 | + |
166 | 173 | private static final int NOT_LAMBDA = 0; |
167 | 174 | private static final int LAMBDA_METHOD = 1; |
168 | 175 | private static final int LAMBDA_CREATION = 3; |
@@ -657,8 +664,10 @@ private String getClassJavaNameForType(Type type) { |
657 | 664 | * anonymous class names |
658 | 665 | * @param isLambda |
659 | 666 | * @param isClassTrulyLocal |
| 667 | + * |
| 668 | + * @return anonymous name only if there are no finals |
660 | 669 | */ |
661 | | - private void processLocalInstance(ASTNode node, ASTNode anonymousClassDeclaration, ITypeBinding binding, |
| 670 | + private String processLocalInstance(ASTNode node, ASTNode anonymousClassDeclaration, ITypeBinding binding, |
662 | 671 | ITypeBinding innerClass, String javaInnerClassName, int lambdaType, boolean isClassTrulyLocal) { |
663 | 672 |
|
664 | 673 | // In the case of local classes, the declaration is dissociated from the |
@@ -701,6 +710,7 @@ private void processLocalInstance(ASTNode node, ASTNode anonymousClassDeclaratio |
701 | 710 | anonymousSuperclassName, anonName); |
702 | 711 | if (lambdaType != LAMBDA_METHOD && !isClassTrulyLocal) |
703 | 712 | buffer.append(")"); // end of line (..., ...) |
| 713 | + return finals == null ? anonName : null; |
704 | 714 | } |
705 | 715 |
|
706 | 716 | /** |
@@ -6808,15 +6818,19 @@ private boolean addLambdaMethodReference(MethodReference node, Expression exp) { |
6808 | 6818 | */ |
6809 | 6819 | private boolean addLambda$class$Method(MethodReference node, ITypeBinding binding, Expression exp, |
6810 | 6820 | ITypeBinding declaringClass, boolean checkFinals) { |
| 6821 | + |
| 6822 | + |
6811 | 6823 | allowClazzNewLambda = (ALLOW_NEW_LAMBDA && getLastCharInBuffer() != '='); |
6812 | 6824 | int pt = buffer.length(); |
6813 | 6825 | buffer.append("(function($class$){"); |
6814 | | - processLocalInstance(node, null, binding, null, null, LAMBDA_METHOD, false); |
| 6826 | + String anonName = processLocalInstance(node, null, binding, null, null, LAMBDA_METHOD, false); |
6815 | 6827 | buffer.append("})("); |
6816 | 6828 | appendFinalMethodQualifier(exp, declaringClass, null, FINAL_ESCAPECACHE | FINAL_LAMBDA); |
6817 | 6829 | buffer.append(")"); |
6818 | 6830 | if (checkFinals && allowClazzNewLambda) |
6819 | 6831 | buffer.setLength(pt); |
| 6832 | + if (anonName != null && ALLOW_LAMBDA_OBJECT_REUSE) |
| 6833 | + addLambdaReuse(pt, anonName); |
6820 | 6834 | return !allowClazzNewLambda; |
6821 | 6835 |
|
6822 | 6836 | } |
@@ -6871,12 +6885,28 @@ public boolean visit(LambdaExpression node) { |
6871 | 6885 | private boolean addLambda$class$Expr(LambdaExpression node, ITypeBinding binding, boolean checkFinals) { |
6872 | 6886 | allowClazzNewLambda = (ALLOW_NEW_LAMBDA && getLastCharInBuffer() != '='); |
6873 | 6887 | int pt = buffer.length(); |
6874 | | - processLocalInstance(node, null, binding, null, null, LAMBDA_EXPRESSION, false); |
| 6888 | + String anonName = processLocalInstance(node, null, binding, null, null, LAMBDA_EXPRESSION, false); |
6875 | 6889 | if (checkFinals && allowClazzNewLambda) |
6876 | 6890 | buffer.setLength(pt); |
| 6891 | + if (anonName != null && ALLOW_LAMBDA_OBJECT_REUSE) |
| 6892 | + addLambdaReuse(pt, anonName); |
6877 | 6893 | return !allowClazzNewLambda; |
6878 | 6894 | } |
6879 | 6895 |
|
| 6896 | + /** |
| 6897 | + * allow reuse of Lambda method and expression objects when they involve no finals |
| 6898 | + * |
| 6899 | + * @param pt |
| 6900 | + * @param anonName |
| 6901 | + */ |
| 6902 | + private void addLambdaReuse(int pt, String anonName) { |
| 6903 | + String tmp = buffer.substring(pt); |
| 6904 | + buffer.setLength(pt); |
| 6905 | + anonName = getFinalJ2SClassName(anonName, FINAL_P); |
| 6906 | + buffer.append("(" + anonName + "$||(" + anonName + "$=(") |
| 6907 | + .append(tmp).append(")))"); |
| 6908 | + } |
| 6909 | + |
6880 | 6910 | private char getLambdaType(ITypeBinding binding) { |
6881 | 6911 | String name = removeBracketsAndFixNullPackageName(getJavaClassNameQualified(binding)); |
6882 | 6912 | if (!name.startsWith("java.util.function.") || name.indexOf("To") >= 0) |
|
0 commit comments