proguard.optimize.evaluation.ParameterTracingInvocationUnit Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-base Show documentation
Show all versions of proguard-base Show documentation
ProGuard is a free shrinker, optimizer, obfuscator, and preverifier for Java bytecode
/*
* ProGuard -- shrinking, optimization, obfuscation, and preverification
* of Java bytecode.
*
* Copyright (c) 2002-2021 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
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package proguard.optimize.evaluation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import proguard.classfile.*;
import proguard.classfile.constant.*;
import proguard.classfile.util.ClassUtil;
import proguard.evaluation.*;
import proguard.evaluation.value.*;
import proguard.optimize.info.ParameterEscapeMarker;
/**
* This InvocationUnit tags reference values like
* {@link ReferenceTracingInvocationUnit}, but adds detail to return values
* from invoked methods.
*
* @see ReferenceTracingInvocationUnit
* @see TracedReferenceValue
* @see InstructionOffsetValue
* @author Eric Lafortune
*/
public class ParameterTracingInvocationUnit
extends ReferenceTracingInvocationUnit
{
private static final Logger logger = LogManager.getLogger(ParameterTracingInvocationUnit.class);
private Value[] parameters = new Value[256];
/**
* Creates a new ParameterTracingInvocationUnit that attaches trace
* values specifying the parameter index to each parameter.
* @param invocationUnit the invocation unit to which invocations will
* be delegated.
*/
public ParameterTracingInvocationUnit(SimplifiedInvocationUnit invocationUnit)
{
super(invocationUnit);
}
// Implementations for SimplifiedInvocationUnit.
@Override
public void setMethodParameterValue(Clazz clazz, AnyMethodrefConstant refConstant, int parameterIndex, Value value)
{
super.setMethodParameterValue(clazz, refConstant, parameterIndex, value);
parameters[parameterIndex] = value;
}
@Override
public Value getMethodReturnValue(Clazz clazz, AnyMethodrefConstant refConstant, String type)
{
Value returnValue =
super.getMethodReturnValue(clazz, refConstant, type);
// We only need to worry about reference values.
if (returnValue.computationalType() != Value.TYPE_REFERENCE)
{
return returnValue;
}
Method referencedMethod = refConstant.referencedMethod;
if (referencedMethod != null)
{
// Start figuring out which trace value to attach to the return value.
int offset =
((TracedReferenceValue)returnValue).getTraceValue().instructionOffsetValue().instructionOffset(0);
// The trace value might be any external value or just a new instance.
InstructionOffsetValue traceValue =
ParameterEscapeMarker.returnsExternalValues(referencedMethod) ? new InstructionOffsetValue(offset | InstructionOffsetValue.FIELD_VALUE) :
ParameterEscapeMarker.returnsNewInstances(referencedMethod) ? new InstructionOffsetValue(offset | InstructionOffsetValue.NEW_INSTANCE) :
null;
long returnedParameters =
ParameterEscapeMarker.getReturnedParameters(referencedMethod);
int parameterCount =
ClassUtil.internalMethodParameterCount(refConstant.getType(clazz), isStatic);
for (int parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
{
if ((returnedParameters & (1L << parameterIndex)) != 0L)
{
Value parameterValue = parameters[parameterIndex];
if (parameterValue instanceof TracedReferenceValue)
{
TracedReferenceValue tracedParameterValue =
(TracedReferenceValue)parameterValue;
if (mayReturnType(refConstant.referencedClass,
referencedMethod,
tracedParameterValue))
{
InstructionOffsetValue parameterTraceValue =
tracedParameterValue.getTraceValue().instructionOffsetValue();
traceValue = traceValue == null ?
parameterTraceValue :
traceValue.generalize(parameterTraceValue);
}
}
}
}
logger.debug("ParameterTracingInvocationUnit.getMethodReturnValue: calling [{}.{}{} ] returns [{} {}]",
refConstant.getClassName(clazz),
refConstant.getName(clazz),
refConstant.getType(clazz),
traceValue,
returnValue
);
// Did we find more detailed information on the return value?
// We should, unless the return value is always null.
if (traceValue != null)
{
return trace(returnValue, traceValue);
}
}
return returnValue;
}
// Small utility methods.
/**
* Returns whether the given method may return the given type of reference
* value
*/
private boolean mayReturnType(Clazz clazz,
Method method,
ReferenceValue referenceValue)
{
String returnType =
ClassUtil.internalMethodReturnType(method.getDescriptor(clazz));
Clazz[] referencedClasses = method instanceof ProgramMethod ?
((ProgramMethod)method).referencedClasses :
((LibraryMethod)method).referencedClasses;
Clazz referencedClass =
referencedClasses == null ||
!ClassUtil.isInternalClassType(returnType) ? null :
referencedClasses[referencedClasses.length - 1];
return referenceValue.instanceOf(returnType,
referencedClass) != Value.NEVER;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy