下面列出了怎么用org.objectweb.asm.tree.InsnList的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public boolean find(String desc, InsnList insns, Collection<AbstractInsnNode> nodes) {
AbstractInsnNode ret = null;
// RETURN opcode varies based on return type, thus we calculate what opcode we're actually looking for by inspecting the target method
int returnOpcode = Type.getReturnType(desc).getOpcode(Opcodes.IRETURN);
ListIterator<AbstractInsnNode> iter = insns.iterator();
while (iter.hasNext()) {
AbstractInsnNode insn = iter.next();
if (insn instanceof InsnNode && insn.getOpcode() == returnOpcode) {
ret = insn;
}
}
// WAT?
if (ret == null) {
throw new InvalidInjectionException(this.context, "TAIL could not locate a valid RETURN in the target method!");
}
nodes.add(ret);
return true;
}
public void storeResultVar(final InsnList instructions, final int opcode) {
assertInitializedInterceptorLocalVariables();
if (opcode == Opcodes.RETURN) {
// void.
loadNull(instructions);
} else if (opcode == Opcodes.ARETURN) {
// object.
dup(instructions);
} else {
if (opcode == Opcodes.LRETURN || opcode == Opcodes.DRETURN) {
// long or double.
dup2(instructions);
} else {
dup(instructions);
}
final Type type = Type.getReturnType(this.methodNode.desc);
box(instructions, type);
}
storeVar(instructions, this.resultVarIndex);
loadNull(instructions);
storeVar(instructions, this.throwableVarIndex);
}
/**
* Compares two objects and performs some action if the objects are NOT the same (uses != to check if not same).
* @param lhs left hand side instruction list -- must leave an object on the stack
* @param rhs right hand side instruction list -- must leave an object on the stack
* @param action action to perform if results of {@code lhs} and {@code rhs} are not equal
* @return instructions instruction list to perform some action if two objects are not equal
* @throws NullPointerException if any argument is {@code null}
*/
public static InsnList ifObjectsNotEqual(InsnList lhs, InsnList rhs, InsnList action) {
Validate.notNull(lhs);
Validate.notNull(rhs);
Validate.notNull(action);
InsnList ret = new InsnList();
LabelNode equalLabelNode = new LabelNode();
ret.add(lhs);
ret.add(rhs);
ret.add(new JumpInsnNode(Opcodes.IF_ACMPEQ, equalLabelNode));
ret.add(action);
ret.add(equalLabelNode);
return ret;
}
void loadArgsVar(final InsnList instructions) {
if (this.argumentTypes.length == 0) {
// null.
loadNull(instructions);
return;
}
push(instructions, this.argumentTypes.length);
// new array
newArray(instructions, OBJECT_TYPE);
for (int i = 0; i < this.argumentTypes.length; i++) {
Type type = this.argumentTypes[i];
dup(instructions);
push(instructions, i);
// loadArg
loadArg(instructions, this.argumentTypes, i);
// box
box(instructions, type);
// arrayStore
arrayStore(instructions, OBJECT_TYPE);
}
}
private InsnList getThrowTraceInstructions() {
InsnList il = new InsnList();
int exceptionVariablePosition = getFistAvailablePosition();
il.add(new VarInsnNode(Opcodes.ASTORE, exceptionVariablePosition));
this.methodOffset++; // Actualizamos el offset
addGetCallback(il);
il.add(new VarInsnNode(Opcodes.ALOAD, this.methodVarIndex));
il.add(new VarInsnNode(Opcodes.ALOAD, exceptionVariablePosition));
il.add(new VarInsnNode(Opcodes.ALOAD, this.executionIdIndex));
il.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
"org/brutusin/instrumentation/Callback", "onThrowableThrown",
"(Ljava/lang/Object;Ljava/lang/Throwable;Ljava/lang/String;)V", false));
il.add(new VarInsnNode(Opcodes.ALOAD, exceptionVariablePosition));
return il;
}
/**
* <p>
* This method injects instructions for add logging for if blocks
* </p>
*
* @param il
* list of instruction lists
* @param nodes
* list of nodes where these instructions needed to be injected
* @param nestingLevel
* nesting level
*/
private void addInsnForIfBlock(InsnList[] il, AbstractInsnNode[] nodes,
int nestingLevel) {
// messages for before, after and within if blocks
int[] msgs = new int[] { MessageConstants.LOG_BEFORE_IF,
MessageConstants.LOG_AFTER_IF, MessageConstants.LOG_IN_IF };
int index = 0;
for (int msg : msgs) {
logger.debug(MessageFormat.format(
InstrumentationMessageLoader.getMessage(msg),
getClassName() + "##" + name, currentIfCount[nestingLevel]));
// for BEFORE_IF, the logging to be injected at the respective label
// node
AbstractInsnNode prevNode = nodes[index];
if (index == 0) {
while (!(prevNode instanceof LabelNode)) {
prevNode = prevNode.getPrevious();
}
}
instructions.insert(prevNode, il[index]);
index++;
}
}
private void desugarClinitToTriggerInterfaceInitializers(
ImmutableList<String> companionsToTriggerInterfaceClinit) {
if (isClinitAlreadyDesugared(companionsToTriggerInterfaceClinit)) {
return;
}
InsnList desugarInsts = new InsnList();
for (String companionClass : companionsToTriggerInterfaceClinit) {
desugarInsts.add(
new MethodInsnNode(
Opcodes.INVOKESTATIC,
companionClass,
InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME,
InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC,
false));
}
if (clInitMethodNode.instructions.size() == 0) {
clInitMethodNode.instructions.insert(new InsnNode(Opcodes.RETURN));
}
clInitMethodNode.instructions.insertBefore(
clInitMethodNode.instructions.getFirst(), desugarInsts);
}
/**
* Generates instructions to pop the result of the method off the stack. This will only generate instructions if the method being
* invoked generates a return value.
* @param invokeInsnNode instruction for the method that was invoked (can either be of type {@link MethodInsnNode} or
* {@link InvokeDynamicInsnNode} -- this is used to determine how many items to pop off the stack
* @return instructions for a pop (only if the method being invoked generates a return value)
* @throws IllegalArgumentException if {@code invokeInsnNode} isn't of type {@link MethodInsnNode} or {@link InvokeDynamicInsnNode}
* @throws NullPointerException if any argument is {@code null}
*/
private static InsnList popMethodResult(AbstractInsnNode invokeInsnNode) {
Validate.notNull(invokeInsnNode);
Type returnType = getReturnTypeOfInvocation(invokeInsnNode);
InsnList ret = new InsnList();
switch (returnType.getSort()) {
case Type.LONG:
case Type.DOUBLE:
ret.add(new InsnNode(Opcodes.POP2));
break;
case Type.VOID:
break;
case Type.METHOD:
throw new IllegalStateException(); // this should never happen
default:
ret.add(new InsnNode(Opcodes.POP));
break;
}
return ret;
}
public void initLocalVariables(final InsnList instructions) {
// find enter & exit instruction.
final LabelNode variableStartLabelNode = new LabelNode();
final LabelNode variableEndLabelNode = new LabelNode();
if(instructions.getFirst() != null) {
instructions.insertBefore(instructions.getFirst(), variableStartLabelNode);
} else {
instructions.insert(variableStartLabelNode);
}
instructions.insert(instructions.getLast(), variableEndLabelNode);
if (!isStatic()) {
addLocalVariable("this", Type.getObjectType(this.declaringClassInternalName).getDescriptor(), variableStartLabelNode, variableEndLabelNode);
}
for (Type type : this.argumentTypes) {
addLocalVariable(JavaAssistUtils.javaClassNameToVariableName(type.getClassName()), type.getDescriptor(), variableStartLabelNode, variableEndLabelNode);
}
}
public static InsnList getImportantList(InsnList list) {
if (list.size() == 0) {
return list;
}
HashMap<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode) {
labels.put((LabelNode) insn, (LabelNode) insn);
}
}
InsnList importantNodeList = new InsnList();
for (AbstractInsnNode insn = list.getFirst(); insn != null; insn = insn.getNext()) {
if (insn instanceof LabelNode || insn instanceof LineNumberNode) {
continue;
}
importantNodeList.add(insn.clone(labels));
}
return importantNodeList;
}
@Override
public void transform(ClassNode cnode) {
Game.logger().info("Transforming IForgeRegistryEntry class for correct NOVA mod id mapping.");
ObfMapping mapping = new ObfMapping("net/minecraftforge/fml/common/registry/IForgeRegistryEntry$Impl", "setRegistryName", "(Ljava/lang/String;)Lnet/minecraftforge/fml/common/registry/IForgeRegistryEntry;");
MethodNode method = ASMHelper.findMethod(mapping, cnode);
if (method == null) {
throw new IllegalStateException("[NOVA] Lookup " + mapping + " failed!");
}
Game.logger().info("Transforming method {}", method.name);
InsnList list = new InsnList();
list.add(new VarInsnNode(ALOAD, 5));
list.add(new MethodInsnNode(INVOKESTATIC, "nova/core/wrapper/mc/forge/v1_11_2/asm/StaticForwarder", "isNovaPrefix", "(Ljava/lang/String;)Z", false));
list.add(new JumpInsnNode(IFNE, (LabelNode) method.instructions.get(120)));
method.instructions.insert(method.instructions.get(101), list);
Game.logger().info("Injected instruction to method: {}", method.name);
}
@Override
public boolean find(String desc, InsnList insns, Collection<AbstractInsnNode> nodes) {
boolean found = false;
// RETURN opcode varies based on return type, thus we calculate what opcode we're actually looking for by inspecting the target method
int returnOpcode = Type.getReturnType(desc).getOpcode(Opcodes.IRETURN);
int ordinal = 0;
ListIterator<AbstractInsnNode> iter = insns.iterator();
while (iter.hasNext()) {
AbstractInsnNode insn = iter.next();
if (insn instanceof InsnNode && insn.getOpcode() == returnOpcode) {
if (this.ordinal == -1 || this.ordinal == ordinal) {
nodes.add(insn);
found = true;
}
ordinal++;
}
}
return found;
}
@Inject(description = "Add hook to override returned value of isRowingBoat")
public void inject(MethodNode main) {
AbstractInsnNode preNode = main.instructions.getFirst();
Objects.requireNonNull(preNode, "Find pattern failed for pre node");
LabelNode jump = new LabelNode();
InsnList insnPre = new InsnList();
// insnPre.add(ASMHelper.call(GETSTATIC,
// TypesHook.Fields.ForgeHaxHooks_isNotRowingBoatActivated));
// insnPre.add(new JumpInsnNode(IFEQ, jump));
insnPre.add(new InsnNode(ICONST_0));
insnPre.add(new InsnNode(IRETURN)); // return false
// insnPre.add(jump);
main.instructions.insert(insnPre);
}
@Override
public void transform() {
AtomicInteger counter = new AtomicInteger();
getClassWrappers().stream().filter(classWrapper -> !excluded(classWrapper)).forEach(classWrapper -> {
ClassNode classNode = classWrapper.getClassNode();
classNode.methods.stream().filter(methodNode -> "<init>".equals(methodNode.name)).forEach(methodNode -> {
InsnList expirationCode = createExpirationInstructions();
methodNode.instructions.insertBefore(methodNode.instructions.getFirst(), expirationCode);
counter.incrementAndGet();
});
});
Main.info(String.format("Added %d expiration code blocks.", counter.get()));
}
private void addFeatureGetSet() {
for (boolean isGet : GET_SET) {
MethodNode mn = new MethodNode(ASM5, ACC_PUBLIC, // Get for non-array value
fi.getGetterSetterName(isGet),
isGet ? ("()" + rangeJavaDescriptor)
: "(" + rangeJavaDescriptor + ")V",
null, null);
InsnList il = mn.instructions;
il.add(new VarInsnNode(ALOAD, 0));
if (isGet) {
il.add(new FieldInsnNode(GETFIELD, typeJavaClassName, featureFieldName, rangeJavaDescriptor));
il.add(new InsnNode(getReturnInst(fi)));
} else {
il.add(new VarInsnNode(getLoadInst(fi), 1)); // load ref, or primitive value
il.add(new FieldInsnNode(PUTFIELD, typeJavaClassName, featureFieldName, rangeJavaDescriptor));
il.add(new InsnNode(RETURN));
}
final boolean is2slotValue = ((TypeImpl) fi.getRange()).isLongOrDouble();
mn.maxStack = isGet ? 1 : is2slotValue ? 3 : 2;
mn.maxLocals = isGet ? 1 : is2slotValue ? 3 : 2;
cn.methods.add(mn);
}
}
private static InsnListSection insnListMatchesL(InsnList haystack, InsnList needle, int start, HashSet<LabelNode> controlFlowLabels) {
int h = start, n = 0;
for (; h < haystack.size() && n < needle.size(); h++) {
AbstractInsnNode insn = haystack.get(h);
if (insn.getType() == 15) {
continue;
}
if (insn.getType() == 8 && !controlFlowLabels.contains(insn)) {
continue;
}
if (!insnEqual(haystack.get(h), needle.get(n))) {
return null;
}
n++;
}
if (n != needle.size()) {
return null;
}
return new InsnListSection(haystack, start, h - 1);
}
private int addMethodParametersVariable(InsnList il) {
il.add(TreeInstructions.getPushInstruction(this.methodArguments.length));
il.add(new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"));
int methodParametersIndex = getFistAvailablePosition();
il.add(new VarInsnNode(Opcodes.ASTORE, methodParametersIndex));
this.mn.maxLocals++;
for (int i = 0; i < this.methodArguments.length; i++) {
il.add(new VarInsnNode(Opcodes.ALOAD, methodParametersIndex));
il.add(TreeInstructions.getPushInstruction(i));
il.add(TreeInstructions.getLoadInst(methodArguments[i],
getArgumentPosition(i)));
MethodInsnNode mNode = TreeInstructions
.getWrapperContructionInst(methodArguments[i]);
if (mNode != null) {
il.add(mNode);
}
il.add(new InsnNode(Opcodes.AASTORE));
}
return methodParametersIndex;
}
private static Set<LabelNode> findJumpTargets(final InsnList instructions) {
final Set<LabelNode> jumpTargets = new HashSet<>();
for (AbstractInsnNode o : instructions) {
if (o instanceof JumpInsnNode) {
jumpTargets.add(((JumpInsnNode) o).label);
} else if (o instanceof TableSwitchInsnNode) {
final TableSwitchInsnNode twn = (TableSwitchInsnNode) o;
jumpTargets.add(twn.dflt);
jumpTargets.addAll(twn.labels);
} else if (o instanceof LookupSwitchInsnNode) {
final LookupSwitchInsnNode lsn = (LookupSwitchInsnNode) o;
jumpTargets.add(lsn.dflt);
jumpTargets.addAll(lsn.labels);
}
}
return jumpTargets;
}
/**
* <p>
* This method provides instruction to log counter information
* </p>
*
* @param className
* Class which has called the logger
* @param methodName
* Method in which the logger has been called
* @param logMethod
* log method
* @param logMsgPrefix
* log message
* @param field
* field which store the counter
* @return Instructions
*/
public static InsnList addCounterLoggingOldApi(String className,
String methodName, String logMethod, String logMsgPrefix,
String field) {
String method = "getMapReduceExecutionInfoOldApi";
InsnList il = new InsnList();
il.add(new LabelNode());
il.add(new LdcInsnNode(className));
il.add(new LdcInsnNode(methodName));
il.add(new LdcInsnNode(logMethod));
il.add(new LdcInsnNode(logMsgPrefix));
il.add(new VarInsnNode(Opcodes.ALOAD, 0));
il.add(new FieldInsnNode(Opcodes.GETFIELD, ConfigurationUtil
.convertQualifiedClassNameToInternalName(className), field,
Type.INT_TYPE.getDescriptor()));
il.add(new MethodInsnNode(Opcodes.INVOKESTATIC, CLASSNAME_LOGUTIL,
method, Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING,
TYPE_STRING, TYPE_STRING, TYPE_STRING, Type.INT_TYPE)));
return il;
}
/**
* Adds the partitioner logging.
*
* @param methodName the method name
* @param isSetup the is setup
* @return the insn list
*/
private InsnList addPartitionerLogging(String methodName, boolean isSetup) {
LOGGER.debug("Add logging of partitioner !!! ");
InsnList il = new InsnList();
if (!isSetup) {
il.add(new LabelNode());
String cSymbol = env.getClassSymbol(getClassName());
String mSymbol = Environment.getMethodSymbol(getClassName(), cSymbol, methodName);
LogInfoBean logBean = new LogInfoBean(cSymbol,
mSymbol,InstrumentationMessageLoader
.getMessage(MessageConstants.MSG_PARTITION_INFO),
null);
il.add(InstrumentUtil.addLoggingForPartitioner(logBean));
}
return il;
}
/**
* Injects a constant modifier at an implied-zero
*
* @param target target method
* @param jumpNode jump instruction (must be IFLT, IFGE, IFGT or IFLE)
*/
private void injectExpandedConstantModifier(Target target, JumpInsnNode jumpNode) {
int opcode = jumpNode.getOpcode();
if (opcode < Opcodes.IFLT || opcode > Opcodes.IFLE) {
throw new InvalidInjectionException(this.info, String.format("%s annotation selected an invalid opcode %s in %s in %s",
this.annotationType, Bytecode.getOpcodeName(opcode), target, this));
}
Extension extraStack = target.extendStack();
final InsnList insns = new InsnList();
insns.add(new InsnNode(Opcodes.ICONST_0));
AbstractInsnNode invoke = this.invokeConstantHandler(Type.getType("I"), target, extraStack, insns, insns);
insns.add(new JumpInsnNode(opcode + ModifyConstantInjector.OPCODE_OFFSET, jumpNode.label));
extraStack.add(1).apply();
target.replaceNode(jumpNode, invoke, insns);
}
/**
* Generates a MONITORENTER instruction, which consumes an Object from the top of the stack.
* @return instructions for a pop
*/
public static InsnList monitorEnter() {
InsnList ret = new InsnList();
ret.add(new InsnNode(Opcodes.MONITORENTER));
return ret;
}
@Override
public boolean find(String desc, InsnList insns, Collection<AbstractInsnNode> nodes) {
boolean found = false;
this.log("BeforeConstant is searching for constants in method with descriptor {}", desc);
ListIterator<AbstractInsnNode> iter = insns.iterator();
for (int ordinal = 0, last = 0; iter.hasNext();) {
AbstractInsnNode insn = iter.next();
boolean matchesInsn = this.expand ? this.matchesConditionalInsn(last, insn) : this.matchesConstantInsn(insn);
if (matchesInsn) {
this.log(" BeforeConstant found a matching constant{} at ordinal {}", this.matchByType != null ? " TYPE" : " value", ordinal);
if (this.ordinal == -1 || this.ordinal == ordinal) {
this.log(" BeforeConstant found {}", Bytecode.describeNode(insn).trim());
nodes.add(insn);
found = true;
}
ordinal++;
}
if (!(insn instanceof LabelNode) && !(insn instanceof FrameNode)) {
last = insn.getOpcode();
}
}
return found;
}
private void createAndFireEvent(
MethodNode method, AbstractInsnNode location, int variableIndex, int nameIndex) {
final InsnList list = new InsnList();
// arguments
InsnList eventObjectArgs = new InsnList();
eventObjectArgs.add(new VarInsnNode(ALOAD, nameIndex));
eventObjectArgs.add(new LdcInsnNode(-1)); // TODO: get original value
list.add(
ASMHelper.newInstance(
Type.getInternalName(RenderTabNameEvent.class),
"(Ljava/lang/String;I)V",
eventObjectArgs));
list.add(new InsnNode(DUP)); // for firing event
list.add(new InsnNode(DUP)); // for getName
list.add(new VarInsnNode(ASTORE, variableIndex));
list.add(ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_fireEvent_v));
list.add(
new MethodInsnNode(
INVOKEVIRTUAL,
Type.getInternalName(RenderTabNameEvent.class),
"getName",
"()Ljava/lang/String;"));
list.add(new VarInsnNode(ASTORE, nameIndex));
method.instructions.insert(location, list);
}
private void addRegexValidations(InsnList patternValidationInsnList,
InstructionsBean insBean, MethodNode methodNode,
boolean instrumentMapreduceRegex, boolean[] isValidated) {
JobConfig jobConfig = (JobConfig)getConfig();
String keyRegex = jobConfig.getMapReduceKeyRegex(getClassName());
String valueRegex = jobConfig.getMapReduceValueRegex(getClassName());
int keyIndex = 0;
int valueIndex = 1;
if (instrumentMapreduceRegex &&
validateRegexValidationClass(jobConfig.getRegex(), getClassName())) {
// Fetching regEx for validating key/value
String[] validators=new String[2];
validators[keyIndex] = keyRegex;
validators[valueIndex] = valueRegex;
int index = 0;
for (boolean isValidationPerformed : isValidated) {
boolean isKey = true;
// Validation of key/value was not done using
// PatternValidator, so we will check if corresponding regEx
// is given apply that
if (!isValidationPerformed) {
if (index == valueIndex) {
isKey = false;
}
patternValidationInsnList.add(addCallForPatternMatcher(
methodNode, insBean, isKey,
validators[index]));
}
index++;
}
}
}
/**
* Generates instruction to enter a monitor (top item on the stack) and store it in the {@link LockState} object sitting in the
* lockstate variable.
* @param markerType debug marker type
* @param lockVars variables for lock/synchpoint functionality
* @return instructions to enter a monitor and store it in the {@link LockState} object
* @throws NullPointerException if any argument is {@code null}
* @throws IllegalArgumentException if lock variables aren't set (the method doesn't contain any monitorenter/monitorexit instructions)
*/
public static InsnList enterMonitorAndStore(MarkerType markerType, LockVariables lockVars) {
Validate.notNull(markerType);
Validate.notNull(lockVars);
Variable lockStateVar = lockVars.getLockStateVar();
Validate.isTrue(lockStateVar != null);
Type clsType = Type.getType(LOCKSTATE_ENTER_METHOD.getDeclaringClass());
Type methodType = Type.getType(LOCKSTATE_ENTER_METHOD);
String clsInternalName = clsType.getInternalName();
String methodDesc = methodType.getDescriptor();
String methodName = LOCKSTATE_ENTER_METHOD.getName();
// NOTE: This adds to the lock state AFTER locking.
return merge(
debugMarker(markerType, "Entering monitor and storing"),
// [obj]
new InsnNode(Opcodes.DUP), // [obj, obj]
new InsnNode(Opcodes.MONITORENTER), // [obj]
new VarInsnNode(Opcodes.ALOAD, lockStateVar.getIndex()), // [obj, lockState]
new InsnNode(Opcodes.SWAP), // [lockState, obj]
new MethodInsnNode(Opcodes.INVOKEVIRTUAL, // []
clsInternalName,
methodName,
methodDesc,
false)
);
}
private boolean isClinitAlreadyDesugared(
ImmutableList<String> companionsToAccessToTriggerInterfaceClinit) {
InsnList instructions = clInitMethodNode.instructions;
if (instructions.size() <= companionsToAccessToTriggerInterfaceClinit.size()) {
// The <clinit> must end with RETURN, so if the instruction count is less than or equal to
// the companion class count, this <clinit> has not been desugared.
return false;
}
Iterator<AbstractInsnNode> iterator = instructions.iterator();
for (String companion : companionsToAccessToTriggerInterfaceClinit) {
if (!iterator.hasNext()) {
return false;
}
AbstractInsnNode insn = iterator.next();
if (!(insn instanceof MethodInsnNode)) {
return false;
}
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
if (methodInsnNode.getOpcode() != Opcodes.INVOKESTATIC
|| !methodInsnNode.owner.equals(companion)
|| !methodInsnNode.name.equals(
InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_NAME)) {
return false;
}
checkState(
methodInsnNode.desc.equals(
InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC),
"Inconsistent method desc: %s vs %s",
methodInsnNode.desc,
InterfaceDesugaring.COMPANION_METHOD_TO_TRIGGER_INTERFACE_CLINIT_DESC);
}
return true;
}
/**
* Generates instructions for printing out a string using {@link System#out}. This is useful for debugging. For example, you
* can print out lines around your instrumented code to make sure that what you think is being run is actually being run.
* @param text debug text generation instruction list -- must leave a String on the stack
* @return instructions to call System.out.println with a string constant
* @throws NullPointerException if any argument is {@code null}
*/
public static InsnList debugPrint(InsnList text) {
Validate.notNull(text);
InsnList ret = new InsnList();
ret.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
ret.add(text);
ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false));
return ret;
}
@Inject(description = "Add callback at top of method")
public void inject(MethodNode node) {
InsnList list = new InsnList();
list.add(new VarInsnNode(ALOAD, 0));
list.add(new VarInsnNode(ALOAD, 1));
list.add(new VarInsnNode(ALOAD, 2));
list.add(ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPlayerBreakingBlock));
node.instructions.insert(list);
}
List<Result> findMatchingCallSites(InsnList instructions, List<LocalVariableAnnotationNode> varAnnotations, Map<Integer, List<AnnotationNode>> paramAnnotations) {
List<Result> result = new ArrayList<Result>();
for (@SuppressWarnings("unchecked") Iterator<AbstractInsnNode> i = instructions.iterator(); i.hasNext(); ) {
AbstractInsnNode ins = i.next();
if (ins instanceof MethodInsnNode) {
MethodInsnNode mins = (MethodInsnNode)ins;
Result entry = findMatchingCallSite(mins, varAnnotations, paramAnnotations);
if (entry != null) {
result.add(entry);
}
}
}
return result;
}