com.newrelic.weave.GeneratedNewFieldMethod Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of newrelic-weaver Show documentation
Show all versions of newrelic-weaver Show documentation
The Weaver of the Java agent.
/*
*
* * Copyright 2020 New Relic Corporation. All rights reserved.
* * SPDX-License-Identifier: Apache-2.0
*
*/
package com.newrelic.weave;
import java.util.Collection;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.MethodNode;
import com.newrelic.weave.utils.WeaveUtils;
/**
* Represents a method that was generated by the compiler to allow accessing or mutating a new field. We keep track of
* these so we can rewrite calls to get/set new fields using the extension class. These methods are generated usually
* to access a field from a nested or inner class. This class is primarily used by
* {@link PreparedExtension#rewriteNewFieldCalls(MethodNode)}.
*
* @see PreparedExtension
*/
class GeneratedNewFieldMethod {
/**
* Generated method, e.g. access$400
*/
public final Method method;
/**
* Name of the new field the method is operating on.
*/
public final String newFieldName;
/**
* Desc of the new field the method is operating on.
*/
public final String newFieldDesc;
/**
* Opcode representing what the method was doing with the new field, either GETSTATIC, PUTSTATIC, GETFIELD, or
* PUTFIELD.
*/
public final int opcode;
/**
* All of the generated mutators I've seen so far return the object that was put. When rewriting these to work with
* the extension class, we will try to keep this behavior.
*
* See {@link PreparedExtension#rewriteNewFieldCalls(MethodNode)} for details on how this is used.
*/
public final boolean returnsPutValue;
private GeneratedNewFieldMethod(Method method, String newFieldName, String newFieldDesc, int opcode) {
this.method = method;
this.newFieldName = newFieldName;
this.newFieldDesc = newFieldDesc;
this.opcode = opcode;
this.returnsPutValue = (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC)
&& method.getReturnType() != Type.VOID_TYPE;
}
/**
* Checks the specified method node to see if it was generated with the explicit purpose of field access. Returns a
* GeneratedNewFieldMethod object representing the operation, or null
if the method is for some other
* purpose other than new field access or mutation.
*
* @param method
* @param newFields
* @return
*/
public static GeneratedNewFieldMethod isGeneratedNewFieldMethod(MethodNode method, Collection newFields) {
// we assume the method is a new field accessor/mutator iff there is exactly one GET or PUT instruction in the
// method body and it operates on a new field
if ((method.access & Opcodes.ACC_SYNTHETIC) == 0 || !WeaveUtils.isSyntheticAccessor(method.name)) {
return null;
}
InsnList instructions = method.instructions;
for (int i = 1; i < instructions.size() - 1; i++) {
AbstractInsnNode instruction = instructions.get(i);
if (instruction.getType() == AbstractInsnNode.FIELD_INSN) {
// must be a new field
String fieldName = ((FieldInsnNode) instruction).name;
if (!newFields.contains(fieldName)) {
return null;
}
// must return after the field instruction
int nextInsnOpcode = instructions.get(i + 1).getOpcode();
return new GeneratedNewFieldMethod(new Method(method.name, method.desc), fieldName,
((FieldInsnNode) instruction).desc, instruction.getOpcode());
} else if (instruction.getType() == AbstractInsnNode.METHOD_INSN) {
return null; // there should be no method invocations
}
}
return null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy