@Override protected void onApply(CtBehavior behavior, Bytecode bytecode) throws BadBytecode { bytecode = BytecodeTools.prepareMethodForBytecode(behavior, bytecode); // loop through the opcodes and change any GT/GE opcodes to ICMPGT/ICMPGE CodeIterator iterator = behavior.getMethodInfo().getCodeAttribute().iterator(); while (iterator.hasNext()) { int index = iterator.next(); int opcode = iterator.byteAt(index); switch (opcode) { case Opcode.IFGT: // overwrite the opcode iterator.writeByte(Opcode.IF_ICMPGT, index); // insert the method call iterator.insertAt(index, bytecode.get()); behavior.getMethodInfo().getCodeAttribute().computeMaxStack(); break; case Opcode.IFGE: // overwrite the opcode iterator.writeByte(Opcode.IF_ICMPGE, index); // insert the method call iterator.insertAt(index, bytecode.get()); behavior.getMethodInfo().getCodeAttribute().computeMaxStack(); break; } } }
public static void rewriteFakeMethod(CodeIterator methodBody, String methodDescriptor) { String ret = DescriptorUtils.getReturnType(methodDescriptor); // if the return type is larger than one then it is not a primitive // so it does not need to be boxed if (ret.length() != 1) { return; } byte ar = (byte) Opcode.ARETURN; byte[] areturn = {ar}; // void methods are special if (ret.equals("V")) { while (methodBody.hasNext()) { try { int index = methodBody.next(); int opcode = methodBody.byteAt(index); // replace a RETURN opcode with // ACONST_NULL // ARETURN // to return a null value if (opcode == Opcode.RETURN) { Bytecode code = new Bytecode(methodBody.get().getConstPool()); code.add(Opcode.ACONST_NULL); code.add(Opcode.ARETURN); methodBody.insertAt(index, code.get()); } } catch (BadBytecode e) { throw new RuntimeException(e); } } } else { while (methodBody.hasNext()) { try { int index = methodBody.next(); int opcode = methodBody.byteAt(index); switch (opcode) { case Opcode.IRETURN: case Opcode.LRETURN: case Opcode.DRETURN: case Opcode.FRETURN: // write a NOP over the old return instruction // insert the boxing code to get an object on the stack Bytecode b = new Bytecode(methodBody.get().getConstPool()); Boxing.box(b, ret.charAt(0)); b.addOpcode(Opcode.ARETURN); methodBody.insertAt(index, b.get()); } } catch (BadBytecode e) { throw new RuntimeException(e); } } } }
private void initExtraHarvest() { try { CtClass terraForming = HookManager.getInstance() .getClassPool() .get("com.wurmonline.server.behaviours.Terraforming"); CtClass[] paramTypes = { HookManager.getInstance().getClassPool().get("com.wurmonline.server.creatures.Creature"), CtPrimitiveType.intType, CtPrimitiveType.intType, CtPrimitiveType.booleanType, CtPrimitiveType.intType, CtPrimitiveType.floatType, HookManager.getInstance().getClassPool().get("com.wurmonline.server.items.Item") }; CtMethod method = terraForming.getMethod( "harvest", Descriptor.ofMethod(CtPrimitiveType.booleanType, paramTypes)); MethodInfo methodInfo = method.getMethodInfo(); CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); CodeIterator codeIterator = codeAttribute.iterator(); LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag); int quantityIndex = -1; for (int i = 0; i < attr.tableLength(); i++) { if ("quantity".equals(attr.variableName(i))) { quantityIndex = attr.index(i); } } if (quantityIndex == -1) { throw new HookException("Quantity variable can not be resolved"); } while (codeIterator.hasNext()) { int pos = codeIterator.next(); int op = codeIterator.byteAt(pos); if (op == CodeIterator.ISTORE) { int fieldRefIdx = codeIterator.byteAt(pos + 1); if (quantityIndex == fieldRefIdx) { Bytecode bytecode = new Bytecode(codeIterator.get().getConstPool()); bytecode.addIconst(extraHarvest); bytecode.add(Bytecode.IADD); codeIterator.insertAt(pos, bytecode.get()); break; } } } } catch (NotFoundException | BadBytecode e) { throw new HookException(e); } }