Skip to content

Commit

Permalink
Add -optimizeaggressively configuration option
Browse files Browse the repository at this point in the history
  • Loading branch information
tvoc-gs authored and Tim Van Den Broecke committed Dec 9, 2022
1 parent 4c6103e commit 3445fa0
Show file tree
Hide file tree
Showing 20 changed files with 200 additions and 95 deletions.
5 changes: 5 additions & 0 deletions base/src/main/java/proguard/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,4 +436,9 @@ public class Configuration
* their respective jars. See {@link proguard.io.ExtraDataEntryNameMap}.
*/
public File extraJar;

/**
* Specifies whether conservative optimization should be applied
*/
public boolean optimizeConservatively = true;
}
1 change: 1 addition & 0 deletions base/src/main/java/proguard/ConfigurationConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public class ConfigurationConstants

public static final String KEEP_KOTLIN_METADATA = "-keepkotlinmetadata";
public static final String DONT_PROCESS_KOTLIN_METADATA = "-dontprocesskotlinmetadata";
public static final String OPTIMIZE_AGGRESSIVELY = "-optimizeaggressively";

public static final String ANY_FILE_KEYWORD = "**";

Expand Down
1 change: 1 addition & 0 deletions base/src/main/java/proguard/ConfigurationParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ else if (ConfigurationConstants.REPACKAGE_CLASSES_OPTION
else if (ConfigurationConstants.PRINT_CONFIGURATION_OPTION .startsWith(nextWord)) configuration.printConfiguration = parseOptionalFile();
else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalFile();
else if (ConfigurationConstants.ADD_CONFIGURATION_DEBUGGING_OPTION .startsWith(nextWord)) configuration.addConfigurationDebugging = parseNoArgument(true);
else if (ConfigurationConstants.OPTIMIZE_AGGRESSIVELY .startsWith(nextWord)) configuration.optimizeConservatively = parseNoArgument(false);
else
{
throw new ParseException("Unknown option " + reader.locationDescription());
Expand Down
3 changes: 2 additions & 1 deletion base/src/main/java/proguard/ConfigurationWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ public void write(Configuration configuration) throws IOException
writeOption(ConfigurationConstants.DUMP_OPTION, configuration.dump);
writeOption(ConfigurationConstants.ADD_CONFIGURATION_DEBUGGING_OPTION, configuration.addConfigurationDebugging);

writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds);
writeOption(ConfigurationConstants.PRINT_SEEDS_OPTION, configuration.printSeeds);
writeOption(ConfigurationConstants.OPTIMIZE_AGGRESSIVELY, !configuration.optimizeConservatively);
writer.println();

// Write the "why are you keeping" options.
Expand Down
12 changes: 7 additions & 5 deletions base/src/main/java/proguard/optimize/Optimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,8 @@ private void optimize(Configuration configuration,
programClassPool.classesAccept(new ProgramClassOptimizationInfoSetter());

programClassPool.classesAccept(new AllMemberVisitor(
new ProgramMemberOptimizationInfoSetter()));
new ProgramMemberOptimizationInfoSetter(
false, configuration.optimizeConservatively)));

if (configuration.assumeNoSideEffects != null)
{
Expand Down Expand Up @@ -735,12 +736,12 @@ private void optimize(Configuration configuration,
new AllMethodVisitor(
new OptimizationInfoMemberFilter(
new MultiMemberVisitor(
new SideEffectMethodMarker(),
new SideEffectMethodMarker(configuration.optimizeConservatively),
new ParameterEscapeMarker()
))));

programClassPool.accept(new InfluenceFixpointVisitor(
new SideEffectVisitorMarkerFactory()));
new SideEffectVisitorMarkerFactory(configuration.optimizeConservatively)));

if (methodMarkingSynchronized)
{
Expand Down Expand Up @@ -1083,7 +1084,8 @@ public ClassVisitor createClassVisitor()
new OptimizationCodeAttributeFilter(
new EvaluationSimplifier(
new PartialEvaluator(valueFactory, loadingInvocationUnit, false),
codeSimplificationAdvancedCounter)))));
codeSimplificationAdvancedCounter,
configuration.optimizeConservatively)))));
}
};

Expand Down Expand Up @@ -1127,7 +1129,7 @@ public ClassVisitor createClassVisitor()
new ParameterTracingInvocationUnit(loadingInvocationUnit),
!codeSimplificationAdvanced,
referenceTracingValueFactory),
true), true, deletedCounter, addedCounter)))));
true, configuration.optimizeConservatively), true, deletedCounter, addedCounter)))));
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,15 @@
class SideEffectVisitorMarkerFactory
implements InfluenceFixpointVisitor.MemberVisitorFactory
{
public SideEffectVisitorMarkerFactory()
private final boolean optimizeConservatively;

/**
* @param optimizeConservatively specifies whether conservative
* optimization should be applied
*/
public SideEffectVisitorMarkerFactory(boolean optimizeConservatively)
{
this.optimizeConservatively = optimizeConservatively;
}

// Implementations for MemberVisitorFactory
Expand All @@ -61,7 +68,8 @@ public MemberVisitor createMemberVisitor(MemberVisitor influencedMethodCollector
// at the cost of some effectiveness (test2209).
//ReadWriteFieldMarker readWriteFieldMarker =
// new ReadWriteFieldMarker(repeatTrigger);
SideEffectMethodMarker sideEffectMethodMarker = new SideEffectMethodMarker(influencedMethodCollector);
SideEffectMethodMarker sideEffectMethodMarker = new SideEffectMethodMarker(influencedMethodCollector,
optimizeConservatively);
ParameterEscapeMarker parameterEscapeMarker =
new ParameterEscapeMarker(partialEvaluator, false, influencedMethodCollector);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class EvaluationShrinker
*/
public EvaluationShrinker()
{
this(new PartialEvaluator(), true, null, null);
this(new PartialEvaluator(), true, false, null, null);
}


Expand All @@ -126,17 +126,20 @@ public EvaluationShrinker()
* evaluator should be run for each
* method, or if some other class is
* already doing this.
* @param optimizeConservatively specifies whether conservative
* optimization should be applied
* @param extraDeletedInstructionVisitor an optional extra visitor for all
* deleted instructions.
* @param extraAddedInstructionVisitor an optional extra visitor for all
* added instructions.
*/
public EvaluationShrinker(PartialEvaluator partialEvaluator,
boolean runPartialEvaluator,
boolean optimizeConservatively,
InstructionVisitor extraDeletedInstructionVisitor,
InstructionVisitor extraAddedInstructionVisitor)
{
this(new InstructionUsageMarker(partialEvaluator, runPartialEvaluator, true),
this(new InstructionUsageMarker(partialEvaluator, runPartialEvaluator, optimizeConservatively),
true,
extraDeletedInstructionVisitor,
extraAddedInstructionVisitor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,44 @@ public class EvaluationSimplifier

private static final Logger logger = LogManager.getLogger(EvaluationSimplifier.class);

private final boolean predictNullPointerExceptions;
private final InstructionVisitor extraInstructionVisitor;

private final PartialEvaluator partialEvaluator;
private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
private final SideEffectInstructionChecker sideEffectInstructionChecker;
private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(true, true);


/**
* Creates a new EvaluationSimplifier.
*
* @param predictNullPointerExceptions specifies whether instructions that will always result in a
* NullPointerException should be replaced with an explicit NullPointerException
*/
public EvaluationSimplifier()
public EvaluationSimplifier(boolean predictNullPointerExceptions)
{
this(new PartialEvaluator(), null);
this(new PartialEvaluator(), null, predictNullPointerExceptions);
}


/**
* Creates a new EvaluationSimplifier.
* @param partialEvaluator the partial evaluator that will
* execute the code and provide
* information about the results.
* @param extraInstructionVisitor an optional extra visitor for all
* simplified instructions.
* @param partialEvaluator the partial evaluator that will
* execute the code and provide
* information about the results.
* @param extraInstructionVisitor an optional extra visitor for all
* simplified instructions.
* @param predictNullPointerExceptions specifies whether instructions that will always result in a
* NullPointerException should be replaced with an explicit NullPointerException
*/
public EvaluationSimplifier(PartialEvaluator partialEvaluator,
InstructionVisitor extraInstructionVisitor)
InstructionVisitor extraInstructionVisitor,
boolean predictNullPointerExceptions)
{
this.partialEvaluator = partialEvaluator;
this.extraInstructionVisitor = extraInstructionVisitor;
this.predictNullPointerExceptions = predictNullPointerExceptions;
this.partialEvaluator = partialEvaluator;
this.extraInstructionVisitor = extraInstructionVisitor;
this.sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true, predictNullPointerExceptions);
}


Expand Down Expand Up @@ -412,11 +421,12 @@ else if (isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
case Instruction.OP_FASTORE:
case Instruction.OP_DASTORE:
case Instruction.OP_AASTORE:
if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
if (predictNullPointerExceptions &&
isNullReference(offset, simpleInstruction.stackPopCount(clazz) - 1))
{
// In case we detected a certain access to a null array, and OPTIMIZE.CONSERVATIVELY
// is enabled, replace the instruction by the explicit exception.
// In case we detected access to an array which we are absolutely certain is a null reference,
// and we are predicting null pointer exceptions, replace the instruction with an explicit
// NullPointerException.
replaceByException(clazz, offset, simpleInstruction, "java/lang/NullPointerException");
}
break;
Expand Down Expand Up @@ -492,7 +502,7 @@ public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute c
case Instruction.OP_INVOKEVIRTUAL:
case Instruction.OP_INVOKESPECIAL:
case Instruction.OP_INVOKEINTERFACE:
if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
if (predictNullPointerExceptions &&
isNullReference(offset, constantInstruction.stackPopCount(clazz) - 1))
{
// In case a method is invoked on a null reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ public class InstructionUsageMarker
private final PartialEvaluator partialEvaluator;
private final boolean runPartialEvaluator;
private final boolean ensureSafetyForVerifier;
private final boolean markExternalSideEffects;
private final PartialEvaluator simplePartialEvaluator;
private final SideEffectInstructionChecker sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true);
private final SideEffectInstructionChecker sideEffectInstructionChecker;
private final MyParameterUsageMarker parameterUsageMarker = new MyParameterUsageMarker();
private final MyInitialUsageMarker initialUsageMarker = new MyInitialUsageMarker();
private final MyProducerMarker producerMarker = new MyProducerMarker();
Expand All @@ -85,22 +86,26 @@ public class InstructionUsageMarker

/**
* Creates a new InstructionUsageMarker.
*
* @param markExternalSideEffects specifies whether instructions with external side effects should be marked
*/
public InstructionUsageMarker()
public InstructionUsageMarker(boolean markExternalSideEffects)
{
this(new PartialEvaluator(), true, true);
this(new PartialEvaluator(), true, true, markExternalSideEffects);
}

/**
* Creates a new InstructionUsageMarker.
* @param partialEvaluator the evaluator to be used for the analysis.
* @param runPartialEvaluator specifies whether to run this evaluator on
* every code attribute that is visited.
* @param partialEvaluator the evaluator to be used for the analysis.
* @param runPartialEvaluator specifies whether to run this evaluator on
* every code attribute that is visited.
* @param markExternalSideEffects specifies whether instructions with external side effects should be marked
*/
public InstructionUsageMarker(PartialEvaluator partialEvaluator,
boolean runPartialEvaluator)
boolean runPartialEvaluator,
boolean markExternalSideEffects)
{
this(partialEvaluator, runPartialEvaluator, true);
this(partialEvaluator, runPartialEvaluator, true, markExternalSideEffects);
}

/**
Expand All @@ -112,14 +117,18 @@ public InstructionUsageMarker(PartialEvaluator partialEvaluator,
* code correctness but are necessary for the
* java verifier. This flag determines whether
* these instructions are visited (default: true).
* @param markExternalSideEffects specifies whether instructions with external side effects should be marked
*/
public InstructionUsageMarker(PartialEvaluator partialEvaluator,
boolean runPartialEvaluator,
boolean ensureSafetyForVerifier)
boolean ensureSafetyForVerifier,
boolean markExternalSideEffects)
{
this.partialEvaluator = partialEvaluator;
this.runPartialEvaluator = runPartialEvaluator;
this.ensureSafetyForVerifier = ensureSafetyForVerifier;
this.partialEvaluator = partialEvaluator;
this.runPartialEvaluator = runPartialEvaluator;
this.ensureSafetyForVerifier = ensureSafetyForVerifier;
this.markExternalSideEffects = markExternalSideEffects;
this.sideEffectInstructionChecker = new SideEffectInstructionChecker(true, true, markExternalSideEffects);
if (ensureSafetyForVerifier)
{
this.simplePartialEvaluator = new PartialEvaluator(new TypedReferenceValueFactory());
Expand Down Expand Up @@ -823,7 +832,7 @@ public void visitAnyMethodrefConstant(Clazz clazz, AnyMethodrefConstant anyMetho
// }

// Is the method invocation really necessary?
if (SideEffectInstructionChecker.OPTIMIZE_CONSERVATIVELY &&
if (markExternalSideEffects &&
referencedMethod != null &&
SideEffectMethodMarker.hasSideEffects(referencedMethod) &&
// Skip if the method was explicitly marked as having no external side-effects.
Expand Down
Loading

0 comments on commit 3445fa0

Please sign in to comment.