下面列出了怎么用org.objectweb.asm.tree.analysis.BasicValue的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public BasicValue newValue(final Type t) {
if (t != null) {
final ValueHolderIden iden = HOLDERS.get(t.getDescriptor());
if (iden != null) {
final ReplacingBasicValue v = ReplacingBasicValue.create(t, iden, index++, valueList);
v.markFunctionReturn();
return v;
}
// We need to track use of the "this" objectref
if ((t.getSort() == Type.OBJECT) && className.equals(t.getInternalName())) {
final ReplacingBasicValue rbValue = ReplacingBasicValue.create(t, null, 0, valueList);
rbValue.setThis();
return rbValue;
}
}
return super.newValue(t);
}
@Override
public BasicValue binaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2) throws AnalyzerException {
/*
* We're looking for the assignment of a local holder objectref to a member variable.
* If we spot that, then the local holder can't be replaced, since we don't (yet)
* have the mechanics to replace the member variable with the holder's members or
* to assign all of them when this happens.
*/
if (insn.getOpcode() == Opcodes.PUTFIELD) {
if (value2.isReference() && (value1 instanceof ReplacingBasicValue)) {
final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value1;
if (possibleThis.isThis() && (value2 instanceof ReplacingBasicValue)) {
// if this is a reference for a holder class, we can't replace it
if (HOLDERS.get(value2.getType().getDescriptor()) != null) {
final ReplacingBasicValue localRef = (ReplacingBasicValue) value2;
localRef.setAssignedToMember();
}
}
}
}
return super.binaryOperation(insn, value1, value2);
}
@Override
public BasicValue naryOperation(final AbstractInsnNode insn,
final List<? extends BasicValue> values) throws AnalyzerException {
if (insn instanceof MethodInsnNode) {
boolean skipOne = insn.getOpcode() != Opcodes.INVOKESTATIC;
// Note if the argument is a holder, and is used as a function argument
for(BasicValue value : values) {
// if non-static method, skip over the receiver
if (skipOne) {
skipOne = false;
continue;
}
if (value instanceof ReplacingBasicValue) {
final ReplacingBasicValue argument = (ReplacingBasicValue) value;
argument.setFunctionArgument();
}
}
}
return super.naryOperation(insn, values);
}
@Override
// Override this method to get unmasked type from BasicInterpreter
public BasicValue newValue(final Type type) {
if (type == null) {
return BasicValue.UNINITIALIZED_VALUE;
}
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
case Type.FLOAT:
case Type.LONG:
case Type.DOUBLE:
case Type.ARRAY:
case Type.OBJECT:
return new BasicValue(type);
default:
throw new AssertionError();
}
}
/**
* Constructs a new {@link CheckMethodAdapter} object. This method adapter
* will perform basic data flow checks. For instance in a method whose
* signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the
* invalid sequence IADD L2I will be detected.
*
* @param access
* the method's access flags.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param cmv
* the method visitor to which this adapter must delegate calls.
* @param labels
* a map of already visited labels (in other methods).
*/
public CheckMethodAdapter(final int access, final String name, final String desc, final MethodVisitor cmv, final Map<Label, Integer> labels) {
this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) {
@Override
public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>(new BasicVerifier());
try {
a.analyze("dummy", this);
} catch (Exception e) {
if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) {
throw new RuntimeException("Data flow checking option requires valid, non zero maxLocals and maxStack values.");
}
e.printStackTrace();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
CheckClassAdapter.printAnalyzerResult(this, a, pw);
pw.close();
throw new RuntimeException(e.getMessage() + ' ' + sw.toString());
}
accept(cmv);
}
}, labels);
this.access = access;
}
public InstructionGraphNode setGraphNode(final AbstractInsnNode insn,
final BasicValue resultValue, final List<BasicValue> predecessors)
{
if (graphNodes == null) {
// initialize with a list of null values
graphNodes = Lists
.newArrayList(new InstructionGraphNode[instructions.size()]);
}
final int index = instructions.indexOf(insn);
InstructionGraphNode node = graphNodes.get(index);
if (node == null) {
node = new InstructionGraphNode(insn, resultValue);
graphNodes.set(index, node);
}
node.addPredecessors(predecessors);
return node;
}
private static ReplacingBasicValue filterReplacement(final BasicValue basicValue) {
if (basicValue instanceof ReplacingBasicValue) {
final ReplacingBasicValue replacingValue = (ReplacingBasicValue) basicValue;
if (replacingValue.isReplaceable()) {
return replacingValue;
}
}
return null;
}
private AbstractInsnNode findArrayCreatorPredecessor(final BasicValue value)
{
final String errorMessage = "Internal error during analysis of rule" +
" method '" + method.name + "', please report this error to" +
" https://github.com/fge/grappa/issues";
if (!(value instanceof InstructionGraphNode))
throw new InvalidGrammarException(errorMessage);
InstructionGraphNode node;
node = (InstructionGraphNode) value;
while (true) {
final int opcode = node.getInstruction().getOpcode();
if (opcode == ANEWARRAY || opcode == NEWARRAY
|| opcode == MULTIANEWARRAY)
break;
final List<InstructionGraphNode> predecessors
= node.getPredecessors();
if (predecessors.size() != 1)
throw new InvalidGrammarException(errorMessage);
node = predecessors.get(0);
}
return node.getInstruction();
}
@Override
public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException {
if (insn.getOpcode() == Opcodes.NEW) {
final TypeInsnNode t = (TypeInsnNode) insn;
// if this is for a holder class, we'll replace it
final ValueHolderIden iden = HOLDERS.get(t.desc);
if (iden != null) {
return ReplacingBasicValue.create(Type.getObjectType(t.desc), iden, index++, valueList);
}
}
return super.newOperation(insn);
}
@Override
public void returnOperation(final AbstractInsnNode insn,
final BasicValue value, final BasicValue expected)
throws AnalyzerException
{
Preconditions.checkState(insn.getOpcode() == ARETURN);
Preconditions.checkState(unwrap(value).getType().equals(
Type.getType(Rule.class)));
Preconditions.checkState(unwrap(expected).getType().equals(
Type.getType(Rule.class)));
Preconditions.checkState(method.getReturnInstructionNode() == null);
method.setReturnInstructionNode(createNode(insn, null, value));
}
@Override
public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value)
throws AnalyzerException {
/*
* We're looking for the assignment of an operator member variable that's a holder to a local
* objectref. If we spot that, we can't replace the local objectref (at least not
* until we do the work to replace member variable holders).
*
* Note that a GETFIELD does not call newValue(), as would happen for a local variable, so we're
* emulating that here.
*/
if ((insn.getOpcode() == Opcodes.GETFIELD) && (value instanceof ReplacingBasicValue)) {
final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value;
if (possibleThis.isThis()) {
final FieldInsnNode fieldInsn = (FieldInsnNode) insn;
if (HOLDERS.get(fieldInsn.desc) != null) {
final BasicValue fetchedField = super.unaryOperation(insn, value);
final ReplacingBasicValue replacingValue =
ReplacingBasicValue.create(fetchedField.getType(), null, -1, valueList);
replacingValue.setAssignedToMember();
return replacingValue;
}
}
}
return super.unaryOperation(insn, value);
}
/**
* Checks the given class.
*
* @param classReader the class to be checked.
* @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
* {@literal null}.
* @param printResults whether to print the results of the bytecode verification.
* @param printWriter where the results (or the stack trace in case of error) must be printed.
*/
public static void verify(
final ClassReader classReader,
final ClassLoader loader,
final boolean printResults,
final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<>();
for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName));
}
for (MethodNode method : methods) {
SimpleVerifier verifier =
new SimpleVerifier(
Type.getObjectType(classNode.name),
syperType,
interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
analyzer.analyze(classNode.name, method);
} catch (AnalyzerException e) {
e.printStackTrace(printWriter);
}
if (printResults) {
printAnalyzerResult(method, analyzer, printWriter);
}
}
printWriter.flush();
}
static void printAnalyzerResult(
final MethodNode method, final Analyzer<BasicValue> analyzer, final PrintWriter printWriter) {
Textifier textifier = new Textifier();
TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(textifier);
printWriter.println(method.name + method.desc);
for (int i = 0; i < method.instructions.size(); ++i) {
method.instructions.get(i).accept(traceMethodVisitor);
StringBuilder stringBuilder = new StringBuilder();
Frame<BasicValue> frame = analyzer.getFrames()[i];
if (frame == null) {
stringBuilder.append('?');
} else {
for (int j = 0; j < frame.getLocals(); ++j) {
stringBuilder.append(getUnqualifiedName(frame.getLocal(j).toString())).append(' ');
}
stringBuilder.append(" : ");
for (int j = 0; j < frame.getStackSize(); ++j) {
stringBuilder.append(getUnqualifiedName(frame.getStack(j).toString())).append(' ');
}
}
while (stringBuilder.length() < method.maxStack + method.maxLocals + 1) {
stringBuilder.append(' ');
}
printWriter.print(Integer.toString(i + 100000).substring(1));
printWriter.print(
" " + stringBuilder + " : " + textifier.text.get(textifier.text.size() - 1));
}
for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
tryCatchBlock.accept(traceMethodVisitor);
printWriter.print(" " + textifier.text.get(textifier.text.size() - 1));
}
printWriter.println();
}
@Override
public ThisValue newValue(Type type) {
ThisValue result = null;
BasicValue original = this.underlying.newValue(type);
if (null != original) {
if (this.isNextThis) {
// WARNING: This is where we assume that we are being asked to describe the "this".
result = ThisValue.createThis(original);
this.isNextThis = false;
} else {
result = ThisValue.createNotThis(original);
}
}
return result;
}
@Override
public ThisValue copyOperation(AbstractInsnNode insn, ThisValue value) throws AnalyzerException {
// We are just moving the value around so it maintains is this/not_this state.
boolean isThis = value.isThis;
BasicValue basic = this.underlying.copyOperation(insn, value.underlying);
return isThis
? ThisValue.createThis(basic)
: ThisValue.createNotThis(basic);
}
@Override
public ThisValue unaryOperation(AbstractInsnNode insn, ThisValue value) throws AnalyzerException {
// These create a different result (possibly null), so isn't this.
BasicValue basic = this.underlying.unaryOperation(insn, value.underlying);
return (null != basic)
? ThisValue.createNotThis(basic)
: null;
}
@Override
public ThisValue binaryOperation(AbstractInsnNode insn, ThisValue value1, ThisValue value2) throws AnalyzerException {
// These create a different result (possibly null), so isn't this.
BasicValue basic = this.underlying.binaryOperation(insn, value1.underlying, value2.underlying);
return (null != basic)
? ThisValue.createNotThis(basic)
: null;
}
@Override
public ThisValue ternaryOperation(AbstractInsnNode insn, ThisValue value1, ThisValue value2, ThisValue value3) throws AnalyzerException {
// These create a different result (possibly null), so isn't this.
BasicValue basic = this.underlying.ternaryOperation(insn, value1.underlying, value2.underlying, value3.underlying);
return (null != basic)
? ThisValue.createNotThis(basic)
: null;
}
@Override
public ThisValue naryOperation(AbstractInsnNode insn, List<? extends ThisValue> values) throws AnalyzerException {
// A new type is created, so definitely not this.
List<BasicValue> basics = values.stream().map((value) -> value.underlying).collect(Collectors.toList());
BasicValue basic = this.underlying.naryOperation(insn, basics);
return (null != basic)
? ThisValue.createNotThis(basic)
: null;
}
@Override
public ThisValue merge(ThisValue value1, ThisValue value2) {
boolean isThis = value1.isThis && value2.isThis;
BasicValue basic = this.underlying.merge(value1.underlying, value2.underlying);
return isThis
? ThisValue.createThis(basic)
: ThisValue.createNotThis(basic);
}
@Test
public void testPartialStack() throws Exception {
Frame<ConstructorThisInterpreter.ThisValue> frame = new Frame<>(LOCAL_COUNT, 1);
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
@SuppressWarnings("unchecked")
Frame<ConstructorThisInterpreter.ThisValue>[] frames = new Frame[] {
frame
};
StackThisTracker tracker = new StackThisTracker(frames);
Assert.assertFalse(tracker.isThisTargetOfGet(0));
Assert.assertFalse(tracker.isThisTargetOfPut(0));
}
@Test
public void testGet() throws Exception {
Frame<ConstructorThisInterpreter.ThisValue> frame = new Frame<>(LOCAL_COUNT, 4);
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createThis(BasicValue.REFERENCE_VALUE));
@SuppressWarnings("unchecked")
Frame<ConstructorThisInterpreter.ThisValue>[] frames = new Frame[] {
frame
};
StackThisTracker tracker = new StackThisTracker(frames);
Assert.assertTrue(tracker.isThisTargetOfGet(0));
Assert.assertFalse(tracker.isThisTargetOfPut(0));
}
@Test
public void testPut() throws Exception {
Frame<ConstructorThisInterpreter.ThisValue> frame = new Frame<>(LOCAL_COUNT, 4);
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createThis(BasicValue.REFERENCE_VALUE));
frame.push(ConstructorThisInterpreter.ThisValue.createNotThis(BasicValue.REFERENCE_VALUE));
@SuppressWarnings("unchecked")
Frame<ConstructorThisInterpreter.ThisValue>[] frames = new Frame[] {
frame
};
StackThisTracker tracker = new StackThisTracker(frames);
Assert.assertFalse(tracker.isThisTargetOfGet(0));
Assert.assertTrue(tracker.isThisTargetOfPut(0));
}
/**
* Checks a given class.
*
* @param cr
* a <code>ClassReader</code> that contains bytecode for the
* analysis.
* @param loader
* a <code>ClassLoader</code> which will be used to load referenced
* classes. This is useful if you are verifiying multiple
* interdependent classes.
* @param dump
* true if bytecode should be printed out not only when errors are
* found.
* @param pw
* write where results going to be printed
*/
public static void verify(final ClassReader cr, final ClassLoader loader, final boolean dump, final PrintWriter pw) {
ClassNode cn = new ClassNode();
cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
Type syperType = cn.superName == null ? null : Type.getObjectType(cn.superName);
List<MethodNode> methods = cn.methods;
List<Type> interfaces = new ArrayList<Type>();
for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
interfaces.add(Type.getObjectType(i.next()));
}
for (int i = 0; i < methods.size(); ++i) {
MethodNode method = methods.get(i);
SimpleVerifier verifier = new SimpleVerifier(Type.getObjectType(cn.name), syperType, interfaces, (cn.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
a.analyze(cn.name, method);
if (!dump) {
continue;
}
} catch (Exception e) {
e.printStackTrace(pw);
}
printAnalyzerResult(method, a, pw);
}
pw.flush();
}
static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, final PrintWriter pw) {
Frame<BasicValue>[] frames = a.getFrames();
Textifier t = new Textifier();
TraceMethodVisitor mv = new TraceMethodVisitor(t);
pw.println(method.name + method.desc);
for (int j = 0; j < method.instructions.size(); ++j) {
method.instructions.get(j).accept(mv);
StringBuilder sb = new StringBuilder();
Frame<BasicValue> f = frames[j];
if (f == null) {
sb.append('?');
} else {
for (int k = 0; k < f.getLocals(); ++k) {
sb.append(getShortName(f.getLocal(k).toString())).append(' ');
}
sb.append(" : ");
for (int k = 0; k < f.getStackSize(); ++k) {
sb.append(getShortName(f.getStack(k).toString())).append(' ');
}
}
while (sb.length() < method.maxStack + method.maxLocals + 1) {
sb.append(' ');
}
pw.print(Integer.toString(j + 100000).substring(1));
pw.print(" " + sb + " : " + t.text.get(t.text.size() - 1));
}
for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
method.tryCatchBlocks.get(j).accept(mv);
pw.print(" " + t.text.get(t.text.size() - 1));
}
pw.println();
}
@Override
public BasicValue newValue(final Type type)
{
if(type == null)
return new BasicValue(Type.getType("java/lang/Object"));
switch(type.getSort())
{
case Type.VOID:
return null;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return BasicValue.INT_VALUE;
case Type.FLOAT:
return BasicValue.FLOAT_VALUE;
case Type.LONG:
return BasicValue.LONG_VALUE;
case Type.DOUBLE:
return BasicValue.DOUBLE_VALUE;
case Type.ARRAY:
case Type.OBJECT:
return new BasicValue(type);
default:
throw new Error("Internal error");
}
}
@Override
public BasicValue binaryOperation(final AbstractInsnNode insn,
final BasicValue value1, final BasicValue value2)
throws AnalyzerException
{
if(insn.getOpcode() == Opcodes.AALOAD)
return new BasicValue(value1.getType().getElementType());
return super.binaryOperation(insn, value1, value2);
}
/**
* Checks the given class.
*
* @param classReader the class to be checked.
* @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
* {@literal null}.
* @param printResults whether to print the results of the bytecode verification.
* @param printWriter where the results (or the stack trace in case of error) must be printed.
*/
public static void verify(
final ClassReader classReader,
final ClassLoader loader,
final boolean printResults,
final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<Type>();
for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName));
}
for (MethodNode method : methods) {
SimpleVerifier verifier =
new SimpleVerifier(
Type.getObjectType(classNode.name),
syperType,
interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
analyzer.analyze(classNode.name, method);
} catch (AnalyzerException e) {
e.printStackTrace(printWriter);
}
if (printResults) {
printAnalyzerResult(method, analyzer, printWriter);
}
}
printWriter.flush();
}
@Override
public BasicValue unaryOperation(final AbstractInsnNode insn,
final BasicValue value)
throws AnalyzerException
{
return createNode(insn, super.unaryOperation(insn, null), value);
}
/**
* Checks the given class.
*
* @param classReader the class to be checked.
* @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
* {@literal null}.
* @param printResults whether to print the results of the bytecode verification.
* @param printWriter where the results (or the stack trace in case of error) must be printed.
*/
public static void verify(
final ClassReader classReader,
final ClassLoader loader,
final boolean printResults,
final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<Type>();
for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName));
}
for (MethodNode method : methods) {
SimpleVerifier verifier =
new SimpleVerifier(
Type.getObjectType(classNode.name),
syperType,
interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}
try {
analyzer.analyze(classNode.name, method);
} catch (AnalyzerException e) {
e.printStackTrace(printWriter);
}
if (printResults) {
printAnalyzerResult(method, analyzer, printWriter);
}
}
printWriter.flush();
}