-
Notifications
You must be signed in to change notification settings - Fork 415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of lambda merging for Kotlin lambda classes #257
base: master
Are you sure you want to change the base?
Changes from 200 commits
7234690
b45bb36
e1e33ef
1f94231
4f7c618
26a90ae
0a68701
a92c963
60d6326
3596717
53bd917
190d8f2
e9f2775
b53739b
a43d0de
438709e
42cdc99
5fe4112
16a95e7
3f54119
c0e70ba
3e7cf66
0d24de5
cdddc97
e8b70e5
fdb8426
43157e8
0cd65e8
a3a662a
506ea6f
94ee87f
604fae1
4b96ecc
d95e082
340fe16
b6e9ea1
878aa06
21ad167
0e41f06
d87fc35
0e67524
2c4c0e3
82b4d0c
764279a
c21c7a9
ef3c2dd
17afac1
6efa42b
29e30dc
eb41035
4d22e85
9199563
f99d34d
3ba9c43
a4741bd
04c434b
ea38c1a
012eeea
b3178bd
1aeee85
af673b6
345e34e
f024bbf
99ae022
5cde21e
44032ff
781f946
90852c1
d23de15
031193e
6e519f0
d9b384a
35736d4
4fd0094
ed1e962
76b6eb9
ef1629b
5ff81d5
e1acdf2
db8a8cd
9a5703e
f3ad14f
e147b4b
1de8e87
6975785
3f3e552
02e996e
aa30700
2010400
9d74ea0
3d0f394
7ba723f
ee4c6a9
a7d453a
3cbec14
514ecbf
bf3fb8a
304a6e2
8e95bfd
0b74332
e91d24a
7e0318e
f3d5717
fb316d9
f834eca
bb64f6c
5f6bb43
6a99a3d
7150365
809f19c
c4832fd
8f2cf0f
52217a5
9869a3e
63168e9
0193e4f
3160366
66bc9b6
fcb6606
971428b
5f50d83
75288d6
698cc26
c7c8745
8295039
029c037
53bae1d
af15b14
fbb14fd
02ad996
01af867
4fce5c1
a8d205c
19525a9
61dc16c
012d183
eaa2f35
6de2bb8
545b67f
9a03344
3b7503b
641e106
0816334
4c1a86d
be44e40
059d918
f6e191b
9b60b16
77f8204
e4c9162
ed6fc74
13032ae
7531f29
1f70c32
7489992
decb49a
0fbed66
ac8e902
089fca6
5ba88c1
d07edaf
d3c257b
a753366
8045e78
b19f341
49debdf
a85084f
b2d8b57
784e884
8d5c4d7
ee581ef
5af6581
8b78b7c
dc7cd78
fb0276d
5888379
43de408
1eaeaca
bf63c23
fb3d726
a216de3
20e0ede
4aae5ca
c985d70
7f46180
99b18e5
705617a
77963f9
8f9fc01
6019bc8
d7c510b
970f5a0
ae4eb58
c61c41c
4a58dd4
b865268
732a889
fb8b417
1b997bb
091794f
7c28e60
b4ac2fb
95fc370
baab6b9
0eb6c83
79f7656
ba4d80f
4426bb6
93112b2
3cf0245
b5f6c25
d99f1a1
ea7bcb2
c28a14f
6944e36
492d73b
210a0a5
16b4138
734cce8
56a90c1
9666d97
8cc582f
64f5038
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,10 @@ jobs: | |
- uses: actions/checkout@v2 | ||
with: | ||
path: proguard-main | ||
- uses: actions/[email protected] | ||
with: | ||
repository: heckej/proguard-core | ||
path: proguard-core | ||
- uses: actions/setup-java@v1 | ||
with: | ||
java-version: 8 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,10 @@ public class ConfigurationConstants | |
public static final String ASSUME_VALUES_OPTION = "-assumevalues"; | ||
public static final String ALLOW_ACCESS_MODIFICATION_OPTION = "-allowaccessmodification"; | ||
public static final String MERGE_INTERFACES_AGGRESSIVELY_OPTION = "-mergeinterfacesaggressively"; | ||
public static final String PRINT_LAMBDAGROUP_MAPPING_OPTION = "-printlambdagroupmapping"; | ||
public static final String MERGE_KOTLIN_LAMBDA_CLASSES_OPTION = "-mergekotlinlambdaclasses"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add the lambda merging to the
|
||
public static final String LAMBDA_MERGING_AFTER_OPTIMIZE_OPTION = "-lambdamergingafteroptimizing"; | ||
heckej marked this conversation as resolved.
Show resolved
Hide resolved
|
||
public static final String LAMBDA_MERGING_ALLOW_UNEXPECTED_METHODS = "-mergelambdaclasseswithunexpectedmethods"; | ||
heckej marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public static final String DONT_OBFUSCATE_OPTION = "-dontobfuscate"; | ||
public static final String PRINT_MAPPING_OPTION = "-printmapping"; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,6 @@ | |
import proguard.configuration.ConfigurationLoggingAdder; | ||
import proguard.evaluation.IncompleteClassHierarchyException; | ||
import proguard.configuration.InitialStateInfo; | ||
import proguard.io.ExtraDataEntryNameMap; | ||
import proguard.logging.Logging; | ||
import proguard.mark.Marker; | ||
import proguard.obfuscate.NameObfuscationReferenceFixer; | ||
|
@@ -39,6 +38,7 @@ | |
import proguard.optimize.LineNumberTrimmer; | ||
import proguard.optimize.Optimizer; | ||
import proguard.optimize.gson.GsonOptimizer; | ||
import proguard.optimize.kotlin.KotlinLambdaMerger; | ||
import proguard.optimize.peephole.LineNumberLinearizer; | ||
import proguard.pass.PassRunner; | ||
import proguard.preverify.*; | ||
|
@@ -177,6 +177,11 @@ public void execute() throws Exception | |
shrink(false); | ||
} | ||
|
||
if (configuration.mergeKotlinLambdaClasses && !configuration.lambdaMergingAfterOptimizing) | ||
{ | ||
mergeKotlinLambdaClasses(); | ||
} | ||
|
||
// Create a matcher for filtering optimizations. | ||
StringMatcher filter = configuration.optimizations != null ? | ||
new ListParser(new NameParser()).parse(configuration.optimizations) : | ||
|
@@ -194,6 +199,11 @@ public void execute() throws Exception | |
linearizeLineNumbers(); | ||
} | ||
|
||
if (configuration.mergeKotlinLambdaClasses && configuration.lambdaMergingAfterOptimizing) | ||
{ | ||
mergeKotlinLambdaClasses(); | ||
} | ||
|
||
if (configuration.obfuscate) | ||
{ | ||
obfuscate(); | ||
|
@@ -424,6 +434,14 @@ private void shrink(boolean afterOptimizer) throws Exception | |
} | ||
} | ||
|
||
/** | ||
* Reduce the size needed to represent Kotlin lambda's. | ||
* The classes that are generated for lambda's with a same structure and from the same package are merged into a group. | ||
*/ | ||
private void mergeKotlinLambdaClasses() throws Exception { | ||
passRunner.run(new KotlinLambdaMerger(configuration), appView); | ||
} | ||
|
||
|
||
/** | ||
* Optimizes usages of the Gson library. | ||
|
@@ -452,6 +470,10 @@ private void optimize() throws Exception | |
{ | ||
shrink(true); | ||
} | ||
if (optimizationPass == configuration.optimizationPasses - 2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to my experience lambda merging has the most impact when it is located in between two last optimisation rounds. That way it benefits from:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing that make the above less obvious (in my opinion) is the fact that it cannot be predicted which round will be the one before last round, such that lambda merging is performed at the end of that round. |
||
{ | ||
mergeKotlinLambdaClasses(); | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package proguard.optimize.kotlin; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add the ProGuard header to all the classes? |
||
|
||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
import proguard.Configuration; | ||
import proguard.classfile.*; | ||
import proguard.classfile.attribute.Attribute; | ||
import proguard.classfile.attribute.CodeAttribute; | ||
import proguard.classfile.attribute.ExceptionsAttribute; | ||
import proguard.classfile.attribute.LineNumberTableAttribute; | ||
import proguard.classfile.attribute.visitor.AttributeVisitor; | ||
import proguard.classfile.editor.ClassBuilder; | ||
import proguard.classfile.editor.ClassEditor; | ||
import proguard.classfile.editor.ConstantPoolEditor; | ||
import proguard.classfile.editor.InstructionSequenceBuilder; | ||
import proguard.classfile.instruction.*; | ||
import proguard.classfile.instruction.visitor.InstructionVisitor; | ||
import proguard.classfile.util.ClassSuperHierarchyInitializer; | ||
import proguard.classfile.util.ClassUtil; | ||
import proguard.classfile.visitor.*; | ||
import proguard.io.ExtraDataEntryNameMap; | ||
import proguard.optimize.info.ProgramClassOptimizationInfo; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class KotlinLambdaClassMerger implements ClassPoolVisitor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add some documentation to the class? |
||
|
||
public static final String NAME_LAMBDA_GROUP = "LambdaGroup"; | ||
private final ClassVisitor lambdaGroupVisitor; | ||
private final ClassVisitor notMergedLambdaVisitor; | ||
private final Configuration configuration; | ||
private final ClassPool programClassPool; | ||
private final ClassPool libraryClassPool; | ||
private final ExtraDataEntryNameMap extraDataEntryNameMap; | ||
private static final Logger logger = LogManager.getLogger(KotlinLambdaClassMerger.class); | ||
|
||
public KotlinLambdaClassMerger(final Configuration configuration, | ||
final ClassPool programClassPool, | ||
final ClassPool libraryClassPool, | ||
final ClassVisitor lambdaGroupVisitor, | ||
final ClassVisitor notMergedLambdaVisitor, | ||
final ExtraDataEntryNameMap extraDataEntryNameMap) | ||
{ | ||
this.configuration = configuration; | ||
this.programClassPool = programClassPool; | ||
this.libraryClassPool = libraryClassPool; | ||
this.lambdaGroupVisitor = lambdaGroupVisitor; | ||
this.notMergedLambdaVisitor = notMergedLambdaVisitor; | ||
this.extraDataEntryNameMap = extraDataEntryNameMap; | ||
} | ||
|
||
@Override | ||
public void visitClassPool(ClassPool lambdaClassPool) | ||
{ | ||
// don't merge lambda's if there is only one or zero | ||
if (lambdaClassPool.size() < 2) | ||
{ | ||
if (notMergedLambdaVisitor != null) { | ||
lambdaClassPool.classesAccept(notMergedLambdaVisitor); | ||
} | ||
return; | ||
} | ||
|
||
// choose a name for the lambda group | ||
// ensure that the lambda group is in the same package as the classes of the class pool | ||
String lambdaGroupName = getPackagePrefixOfClasses(lambdaClassPool) + NAME_LAMBDA_GROUP; | ||
logger.info("Creating lambda group with name {}", ClassUtil.externalClassName(lambdaGroupName)); | ||
heckej marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// create a lambda group builder | ||
KotlinLambdaGroupBuilder lambdaGroupBuilder = new KotlinLambdaGroupBuilder(lambdaGroupName, | ||
this.configuration, | ||
this.programClassPool, | ||
this.libraryClassPool, | ||
this.extraDataEntryNameMap, | ||
this.notMergedLambdaVisitor); | ||
|
||
// visit each lambda of this package to add their implementations to the lambda group | ||
lambdaClassPool.classesAccept(lambdaGroupBuilder); | ||
|
||
ProgramClass lambdaGroup = lambdaGroupBuilder.build(); | ||
|
||
ProgramClassOptimizationInfo.setProgramClassOptimizationInfo(lambdaGroup); | ||
ProgramClassOptimizationInfo optimizationInfo = | ||
ProgramClassOptimizationInfo.getProgramClassOptimizationInfo(lambdaGroup); | ||
optimizationInfo.setLambdaGroup(lambdaGroup); | ||
|
||
// let the lambda group visitor visit the newly created lambda group | ||
this.lambdaGroupVisitor.visitProgramClass(lambdaGroup); | ||
} | ||
|
||
private static String getPackagePrefixOfClasses(ClassPool classPool) | ||
{ | ||
// Assume that all classes in the given class pool are in the same package. | ||
String someClassName = classPool.classNames().next(); | ||
return ClassUtil.internalPackagePrefix(someClassName); | ||
} | ||
} | ||
heckej marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.