proguard.classfile.editor.VariableEditor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-core Show documentation
Show all versions of proguard-core Show documentation
ProGuardCORE is a free library to read, analyze, modify, and write Java class files.
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2020 Guardsquare NV
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package proguard.classfile.editor;
import java.util.Arrays;
import proguard.classfile.*;
import proguard.classfile.attribute.*;
import proguard.classfile.attribute.visitor.AttributeVisitor;
/**
* This {@link AttributeVisitor} accumulates specified changes to local variables, and then applies
* these accumulated changes to the code attributes that it visits.
*
* @author Eric Lafortune
*/
public class VariableEditor implements AttributeVisitor {
private boolean modified;
private boolean[] deleted = new boolean[ClassEstimates.TYPICAL_VARIABLES_SIZE];
private int[] variableMap = new int[ClassEstimates.TYPICAL_VARIABLES_SIZE];
private final VariableRemapper variableRemapper = new VariableRemapper();
/**
* Resets the accumulated code changes.
*
* @param maxLocals the length of the local variable frame that will be edited next.
*/
public void reset(int maxLocals) {
// Try to reuse the previous array.
if (deleted.length < maxLocals) {
// Create a new array.
deleted = new boolean[maxLocals];
} else {
// Reset the array.
Arrays.fill(deleted, 0, maxLocals, false);
}
modified = false;
}
/**
* Remembers to delete the given variable.
*
* @param variableIndex the index of the variable to be deleted.
*/
public void deleteVariable(int variableIndex) {
deleted[variableIndex] = true;
modified = true;
}
/** Returns whether the given variable at the given offset will be deleted. */
public boolean isDeleted(int instructionOffset) {
return deleted[instructionOffset];
}
// Implementations for AttributeVisitor.
public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) {
// Avoid doing any work if nothing is changing anyway.
if (!modified) {
return;
}
int oldMaxLocals = codeAttribute.u2maxLocals;
// Make sure there is a sufficiently large variable map.
if (variableMap.length < oldMaxLocals) {
variableMap = new int[oldMaxLocals];
}
// Fill out the variable map.
int newVariableIndex = 0;
for (int oldVariableIndex = 0; oldVariableIndex < oldMaxLocals; oldVariableIndex++) {
variableMap[oldVariableIndex] = deleted[oldVariableIndex] ? -1 : newVariableIndex++;
}
// Set the map.
variableRemapper.setVariableMap(variableMap);
// Remap the variables.
variableRemapper.visitCodeAttribute(clazz, method, codeAttribute);
// Update the length of local variable frame.
codeAttribute.u2maxLocals = newVariableIndex;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy