mirror of
https://github.com/Guardsquare/proguard.git
synced 2026-03-13 09:50:34 +08:00
Set the IS_CLASS_AVAILABLE processing flag
This commit is contained in:
committed by
Tim Van Den Broecke
parent
1cbd6f7a68
commit
9b8f80229a
@@ -2,7 +2,7 @@
|
||||
* ProGuard -- shrinking, optimization, obfuscation, and preverification
|
||||
* of Java bytecode.
|
||||
*
|
||||
* Copyright (c) 2002-2020 Guardsquare NV
|
||||
* Copyright (c) 2002-2022 Guardsquare NV
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
@@ -22,21 +22,56 @@ package proguard.mark;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import proguard.*;
|
||||
import proguard.classfile.*;
|
||||
import proguard.AppView;
|
||||
import proguard.Configuration;
|
||||
import proguard.KeepClassSpecificationVisitorFactory;
|
||||
import proguard.classfile.AccessConstants;
|
||||
import proguard.classfile.ClassConstants;
|
||||
import proguard.classfile.ClassPool;
|
||||
import proguard.classfile.Clazz;
|
||||
import proguard.classfile.attribute.Attribute;
|
||||
import proguard.classfile.attribute.visitor.*;
|
||||
import proguard.classfile.kotlin.*;
|
||||
import proguard.classfile.kotlin.visitor.*;
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor;
|
||||
import proguard.classfile.attribute.visitor.AttributeNameFilter;
|
||||
import proguard.classfile.attribute.visitor.AttributeProcessingFlagFilter;
|
||||
import proguard.classfile.attribute.visitor.AttributeVisitor;
|
||||
import proguard.classfile.kotlin.KotlinClassKindMetadata;
|
||||
import proguard.classfile.kotlin.KotlinConstants;
|
||||
import proguard.classfile.kotlin.KotlinDeclarationContainerMetadata;
|
||||
import proguard.classfile.kotlin.KotlinFunctionMetadata;
|
||||
import proguard.classfile.kotlin.KotlinMetadata;
|
||||
import proguard.classfile.kotlin.KotlinSyntheticClassKindMetadata;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionToDefaultMethodVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionToMethodVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinMetadataVisitor;
|
||||
import proguard.classfile.kotlin.visitor.ReferencedKotlinMetadataVisitor;
|
||||
import proguard.classfile.util.AllParameterVisitor;
|
||||
import proguard.classfile.visitor.*;
|
||||
import proguard.classfile.visitor.AllMemberVisitor;
|
||||
import proguard.classfile.visitor.ClassAccessFilter;
|
||||
import proguard.classfile.visitor.ClassNameFilter;
|
||||
import proguard.classfile.visitor.ClassPoolVisitor;
|
||||
import proguard.classfile.visitor.ClassProcessingFlagFilter;
|
||||
import proguard.classfile.visitor.ClassVisitor;
|
||||
import proguard.classfile.visitor.MemberAccessFilter;
|
||||
import proguard.classfile.visitor.MemberDescriptorReferencedClassVisitor;
|
||||
import proguard.classfile.visitor.MemberNameFilter;
|
||||
import proguard.classfile.visitor.MemberProcessingFlagFilter;
|
||||
import proguard.classfile.visitor.MemberToClassVisitor;
|
||||
import proguard.classfile.visitor.MemberVisitor;
|
||||
import proguard.classfile.visitor.MultiClassPoolVisitor;
|
||||
import proguard.classfile.visitor.MultiClassVisitor;
|
||||
import proguard.classfile.visitor.MultiMemberVisitor;
|
||||
import proguard.classfile.visitor.NamedMethodVisitor;
|
||||
import proguard.pass.Pass;
|
||||
import proguard.util.*;
|
||||
import proguard.util.ProcessingFlagSetter;
|
||||
import proguard.util.ProcessingFlags;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static proguard.util.ProcessingFlags.*;
|
||||
import static proguard.util.ProcessingFlags.DONT_OBFUSCATE;
|
||||
import static proguard.util.ProcessingFlags.DONT_OPTIMIZE;
|
||||
import static proguard.util.ProcessingFlags.DONT_SHRINK;
|
||||
import static proguard.util.ProcessingFlags.INJECTED;
|
||||
|
||||
/**
|
||||
* This pass translates the keep rules and other class specifications from the
|
||||
@@ -91,6 +126,13 @@ public class Marker implements Pass
|
||||
appView.libraryClassPool.classesAccept(classVisitor);
|
||||
}
|
||||
|
||||
// Mark members that can be safely used for generalization,
|
||||
// but only if optimization is enabled.
|
||||
if (configuration.optimize)
|
||||
{
|
||||
markSafeGeneralizationMembers(appView.programClassPool, appView.libraryClassPool);
|
||||
}
|
||||
|
||||
if (configuration.keepKotlinMetadata)
|
||||
{
|
||||
disableOptimizationForKotlinFeatures(appView.programClassPool, appView.libraryClassPool);
|
||||
@@ -187,6 +229,24 @@ public class Marker implements Pass
|
||||
}
|
||||
|
||||
|
||||
private void markSafeGeneralizationMembers(ClassPool programClassPool,
|
||||
ClassPool libraryClassPool)
|
||||
{
|
||||
// Program classes are always available and safe to generalize/specialize from/to.
|
||||
ClassVisitor isClassAvailableMarker =
|
||||
new AllMemberVisitor(
|
||||
new ProcessingFlagSetter(ProcessingFlags.IS_CLASS_AVAILABLE));
|
||||
|
||||
programClassPool.classesAccept(isClassAvailableMarker);
|
||||
|
||||
if (!configuration.optimizeConservatively)
|
||||
{
|
||||
libraryClassPool.classesAccept(isClassAvailableMarker);
|
||||
}
|
||||
// TODO: Mark library class members where appropriate in the conservative case.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method will disable optimization for all Kotlin components where required,
|
||||
* such as for $default methods.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* ProGuard -- shrinking, optimization, obfuscation, and preverification
|
||||
* of Java bytecode.
|
||||
*
|
||||
* Copyright (c) 2002-2021 Guardsquare NV
|
||||
* Copyright (c) 2002-2022 Guardsquare NV
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
@@ -22,9 +22,18 @@ package proguard.optimize;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import proguard.classfile.*;
|
||||
import proguard.classfile.editor.*;
|
||||
import proguard.classfile.util.*;
|
||||
import proguard.classfile.AccessConstants;
|
||||
import proguard.classfile.ClassConstants;
|
||||
import proguard.classfile.Clazz;
|
||||
import proguard.classfile.ProgramClass;
|
||||
import proguard.classfile.ProgramField;
|
||||
import proguard.classfile.ProgramMember;
|
||||
import proguard.classfile.ProgramMethod;
|
||||
import proguard.classfile.TypeConstants;
|
||||
import proguard.classfile.editor.ConstantPoolEditor;
|
||||
import proguard.classfile.editor.MemberReferenceFixer;
|
||||
import proguard.classfile.util.ClassUtil;
|
||||
import proguard.classfile.util.InternalTypeEnumeration;
|
||||
import proguard.classfile.visitor.MemberVisitor;
|
||||
import proguard.evaluation.value.Value;
|
||||
import proguard.optimize.evaluation.StoringInvocationUnit;
|
||||
@@ -132,7 +141,7 @@ implements MemberVisitor
|
||||
|
||||
if (valueClass != null &&
|
||||
valueClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(fieldType)) &&
|
||||
(valueClass.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(programField.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
logger.debug("MemberDescriptorSpecializer [{}.{} {}] -> {}",
|
||||
programClass.getName(),
|
||||
@@ -179,7 +188,7 @@ implements MemberVisitor
|
||||
InternalTypeEnumeration parameterTypeEnumeration =
|
||||
new InternalTypeEnumeration(descriptor);
|
||||
|
||||
StringBuffer newDescriptorBuffer = new StringBuffer(descriptor.length());
|
||||
StringBuilder newDescriptorBuffer = new StringBuilder(descriptor.length());
|
||||
newDescriptorBuffer.append(TypeConstants.METHOD_ARGUMENTS_OPEN);
|
||||
|
||||
while (parameterTypeEnumeration.hasMoreTypes())
|
||||
@@ -201,7 +210,7 @@ implements MemberVisitor
|
||||
|
||||
if (valueClass != null &&
|
||||
valueClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(parameterType)) &&
|
||||
(valueClass.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(programMethod.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
logger.debug("MemberDescriptorSpecializer [{}.{}{}]: parameter #{}: {} -> {}",
|
||||
programClass.getName(),
|
||||
@@ -318,7 +327,7 @@ implements MemberVisitor
|
||||
return type;
|
||||
}
|
||||
|
||||
return ClassUtil.internalTypeFromClassType(valueType);
|
||||
return valueType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package proguard.optimize
|
||||
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import proguard.classfile.AccessConstants
|
||||
import proguard.classfile.Clazz
|
||||
import proguard.classfile.Member
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
import proguard.classfile.attribute.visitor.DebugAttributeVisitor
|
||||
import proguard.classfile.visitor.AllMemberVisitor
|
||||
import proguard.classfile.visitor.AllMethodVisitor
|
||||
import proguard.classfile.visitor.ClassAccessFilter
|
||||
import proguard.classfile.visitor.MemberNameFilter
|
||||
import proguard.classfile.visitor.MemberVisitor
|
||||
import proguard.classfile.visitor.ParallelAllClassVisitor.ClassVisitorFactory
|
||||
import proguard.evaluation.InvocationUnit
|
||||
import proguard.evaluation.PartialEvaluator
|
||||
import proguard.evaluation.value.ParticularValueFactory
|
||||
import proguard.evaluation.value.ValueFactory
|
||||
import proguard.optimize.evaluation.StoringInvocationUnit
|
||||
import proguard.optimize.info.ProgramClassOptimizationInfoSetter
|
||||
import proguard.optimize.info.ProgramMemberOptimizationInfoSetter
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import proguard.util.ProcessingFlagSetter
|
||||
import proguard.util.ProcessingFlags.IS_CLASS_AVAILABLE
|
||||
|
||||
class MemberDescriptorSpecializerTest : FreeSpec({
|
||||
"Given a method with a more general parameter type than its use" - {
|
||||
val (programClassPool, libraryClassPool) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Test.java",
|
||||
"""
|
||||
public class Test {
|
||||
public static void main(String[] args) {
|
||||
foo(new Foo());
|
||||
}
|
||||
public static void foo(Bar foo) {
|
||||
System.out.println(foo);
|
||||
}
|
||||
}
|
||||
|
||||
class Bar { }
|
||||
|
||||
class Foo extends Bar { }
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
|
||||
"When specializing the member descriptors" - {
|
||||
|
||||
// Mark all members as available.
|
||||
programClassPool.classesAccept(AllMemberVisitor(ProcessingFlagSetter(IS_CLASS_AVAILABLE)))
|
||||
|
||||
// Setup the OptimizationInfo on the classes
|
||||
val keepMarker = KeepMarker()
|
||||
libraryClassPool.classesAccept(keepMarker)
|
||||
libraryClassPool.classesAccept(AllMemberVisitor(keepMarker))
|
||||
|
||||
programClassPool.classesAccept(ProgramClassOptimizationInfoSetter())
|
||||
programClassPool.classesAccept(AllMemberVisitor(ProgramMemberOptimizationInfoSetter()))
|
||||
|
||||
// Create the optimization as in Optimizer
|
||||
val fillingOutValuesClassVisitor = ClassVisitorFactory {
|
||||
val valueFactory: ValueFactory = ParticularValueFactory()
|
||||
val storingInvocationUnit: InvocationUnit = StoringInvocationUnit(
|
||||
valueFactory,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)
|
||||
ClassAccessFilter(
|
||||
0, AccessConstants.SYNTHETIC,
|
||||
AllMethodVisitor(
|
||||
AllAttributeVisitor(
|
||||
DebugAttributeVisitor(
|
||||
"Filling out fields, method parameters, and return values",
|
||||
PartialEvaluator(
|
||||
valueFactory, storingInvocationUnit,
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
programClassPool.classesAccept(fillingOutValuesClassVisitor.createClassVisitor())
|
||||
|
||||
// Specialize class member descriptors, based on partial evaluation.
|
||||
programClassPool.classesAccept(
|
||||
AllMemberVisitor(
|
||||
OptimizationInfoMemberFilter(
|
||||
MemberDescriptorSpecializer(
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
"Then the member descriptor should be correctly specialised" {
|
||||
lateinit var memberDescriptor: String
|
||||
programClassPool.classAccept(
|
||||
"Test",
|
||||
AllMemberVisitor(
|
||||
MemberNameFilter(
|
||||
"foo*",
|
||||
object : MemberVisitor {
|
||||
override fun visitAnyMember(clazz: Clazz, member: Member) {
|
||||
memberDescriptor = member.getDescriptor(clazz)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
memberDescriptor shouldBe "(LFoo;)V"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -11,6 +11,7 @@
|
||||
- Fix `-keepparameternames` to keep Kotlin interface parameter names.
|
||||
- Fix potential `NullPointerException` while processing enum classes with invalid Kotlin metadata.
|
||||
- Fix potential `Instruction has invalid constant index size` error during GSON optimization.
|
||||
- Fix member specialization & generalization optimizations.
|
||||
|
||||
## Version 7.3.0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user