Beispiel #1
0
  private void hookSendMessage(ClassNode cn) {
    Pattern p =
        new PatternBuilder()
            .add(
                new InstructionElement(INVOKESTATIC),
                new AnyElement(),
                new LdcElement(new LdcInsnNode("Chat")),
                new InstructionElement(INVOKEVIRTUAL))
            .build();

    for (MethodNode mn : cn.methods) {
      if (!p.contains(mn.instructions)) continue;

      int offset = p.getOffset(mn.instructions) + 4;

      InsnList inject = new InsnList();
      inject.add(new VarInsnNode(ALOAD, 2));
      inject.add(
          new MethodInsnNode(
              INVOKESTATIC,
              "me/themallard/bitmmo/impl/plugin/chathook/ChatHookManager",
              "onChatMessage",
              "(Ljava/lang/String;)V",
              false));

      mn.instructions.insert(mn.instructions.get(offset), inject);
    }
  }
Beispiel #2
0
  private void hookRecieveMessage(ClassNode cn) {
    Pattern p =
        new PatternBuilder()
            .add(
                new InstructionElement(DUP),
                new InstructionElement(INVOKESPECIAL),
                new LdcElement(new LdcInsnNode("\n")))
            .build();

    for (MethodNode mn : cn.methods) {
      if (!p.contains(mn.instructions)) continue;

      int offset = p.getOffset(mn.instructions);

      MethodInsnNode getMsgInsn = (MethodInsnNode) mn.instructions.get(offset + 5);

      InsnList inject = new InsnList();
      inject.add(new VarInsnNode(ALOAD, 1));
      inject.add(
          new MethodInsnNode(
              INVOKEVIRTUAL, getMsgInsn.owner, getMsgInsn.name, "()Ljava/lang/String;", false));
      inject.add(
          new MethodInsnNode(
              INVOKESTATIC,
              "me/themallard/bitmmo/impl/plugin/chathook/ChatHookManager",
              "onReceiveMessage",
              "(Ljava/lang/String;)V",
              false));

      mn.instructions.insertBefore(mn.instructions.get(offset), inject);
    }
  }
  @Override
  public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (transformedName.equals("net.minecraft.block.BlockDynamicLiquid")
        && CoreLoadingPlugin.util.getBoolean("FiniteWater", false)) {
      ClassReader reader = new ClassReader(bytes);
      ClassNode node = new ClassNode();
      reader.accept(node, 0);
      InsnList getSmallestFlowDecay = new InsnList();

      getSmallestFlowDecay.add(new VarInsnNode(ALOAD, 0));
      getSmallestFlowDecay.add(new InsnNode(ICONST_0));
      getSmallestFlowDecay.add(
          new FieldInsnNode(
              PUTFIELD, "net/minecraft/block/BlockDynamicLiquid", "field_149815_a", "I"));

      for (MethodNode method : node.methods)
        if ("func_149810_a"
            .equals(
                FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(name, method.name, method.desc)))
          method.instructions.insertBefore(method.instructions.getFirst(), getSmallestFlowDecay);

      ClassWriter writer = new ClassWriter(0);
      node.accept(writer);
      return writer.toByteArray();
    }

    return bytes;
  }
  /** {@inheritDoc} */
  @Override
  public List<Mutation> apply(
      MethodNode mn,
      String className,
      String methodName,
      BytecodeInstruction instruction,
      Frame frame) {
    List<Mutation> mutations = new LinkedList<Mutation>();

    FieldInsnNode node = (FieldInsnNode) instruction.getASMNode();
    Type fieldType = Type.getType(node.desc);

    // insert mutation into bytecode with conditional
    InsnList mutation = new InsnList();
    logger.debug("Mutation deletefield for statement " + node.name + node.desc);
    if (node.getOpcode() == Opcodes.GETFIELD) {
      logger.debug("Deleting source of type " + node.owner);
      mutation.add(new InsnNode(Opcodes.POP));
    }
    mutation.add(getDefault(fieldType));
    // insert mutation into pool
    Mutation mutationObject =
        MutationPool.addMutation(
            className,
            methodName,
            NAME + " " + node.name + node.desc,
            instruction,
            mutation,
            getInfectionDistance(node, mutation));

    mutations.add(mutationObject);
    return mutations;
  }
  private int firePeacefulRegenEventAndStoreEventBefore(
      MethodNode method, AbstractInsnNode injectPoint, LabelNode endLabel) {
    // create  variable
    LabelNode peacefulRegenEventStart = new LabelNode();
    LocalVariableNode peacefulRegenEvent =
        new LocalVariableNode(
            "peacefulRegenEvent",
            Type.getDescriptor(HealthRegenEvent.PeacefulRegen.class),
            null,
            peacefulRegenEventStart,
            endLabel,
            method.maxLocals);
    method.maxLocals += 1;
    method.localVariables.add(peacefulRegenEvent);

    InsnList toInject = new InsnList();

    // HealthRegenEvent.PeacefulRegen peacefulRegenEvent = Hooks.firePeacefulRegenEvent(this);
    toInject.add(new VarInsnNode(ALOAD, 0));
    toInject.add(
        new MethodInsnNode(
            INVOKESTATIC,
            Type.getInternalName(Hooks.class),
            "firePeacefulRegenEvent",
            "(Lnet/minecraft/entity/player/EntityPlayer;)Lsqueek/applecore/api/hunger/HealthRegenEvent$PeacefulRegen;",
            false));
    toInject.add(new VarInsnNode(ASTORE, peacefulRegenEvent.index));
    toInject.add(peacefulRegenEventStart);

    method.instructions.insertBefore(injectPoint, toInject);

    return peacefulRegenEvent.index;
  }
  @Override
  public void transform(ClassNode cnode) {
    System.out.println("[NOVA] Transforming Chunk class for chunkModified event.");

    ObfMapping obfMap = new ObfMapping("apx", "a", "(IIILaji;I)Z");
    ObfMapping srgMap =
        new ObfMapping(
            "net/minecraft/world/chunk/Chunk",
            "func_150807_a",
            "(IIILnet/minecraft/block/Block;I)Z");

    MethodNode method = ASMHelper.findMethod(obfMap, cnode);

    if (method == null) {
      System.out.println(
          "[NOVA] Lookup " + obfMap + " failed. You are probably in a deobf environment.");
      method = ASMHelper.findMethod(srgMap, cnode);

      if (method == null) {
        System.out.println("[NOVA] Lookup " + srgMap + " failed!");
      }
    }

    System.out.println("[NOVA] Found method " + method.name);

    InsnList list = new InsnList();
    list.add(new VarInsnNode(ALOAD, 0));
    list.add(new VarInsnNode(ILOAD, 1));
    list.add(new VarInsnNode(ILOAD, 2));
    list.add(new VarInsnNode(ILOAD, 3));
    list.add(new VarInsnNode(ALOAD, 8));
    list.add(new VarInsnNode(ILOAD, 9));
    list.add(new VarInsnNode(ALOAD, 4));
    list.add(new VarInsnNode(ILOAD, 5));
    list.add(
        new MethodInsnNode(
            INVOKESTATIC,
            "nova/wrapper/mc1710/asm/StaticForwarder",
            "chunkSetBlockEvent",
            "(Lnet/minecraft/world/chunk/Chunk;IIILnet/minecraft/block/Block;ILnet/minecraft/block/Block;I)V",
            false));

    AbstractInsnNode lastInsn = method.instructions.getLast();
    while (lastInsn instanceof LabelNode || lastInsn instanceof LineNumberNode) {
      lastInsn = lastInsn.getPrevious();
    }

    if (ASMHelper.isReturn(lastInsn)) {
      method.instructions.insertBefore(lastInsn, list);
    } else {
      method.instructions.insert(list);
    }

    System.out.println("[NOVA] Injected instruction to method: " + method.name);
  }
  /** {@inheritDoc} */
  @Override
  public List<Mutation> apply(
      MethodNode mn,
      String className,
      String methodName,
      BytecodeInstruction instruction,
      Frame frame) {
    JumpInsnNode node = (JumpInsnNode) instruction.getASMNode();
    List<Mutation> mutations = new LinkedList<Mutation>();
    LabelNode target = node.label;

    boolean isBoolean =
        frame.getStack(frame.getStackSize() - 1) == BooleanValueInterpreter.BOOLEAN_VALUE;

    for (Integer op : getOperators(node.getOpcode(), isBoolean)) {
      logger.debug("Adding replacement " + op);
      if (op >= 0) {
        // insert mutation into bytecode with conditional
        JumpInsnNode mutation = new JumpInsnNode(op, target);
        // insert mutation into pool
        Mutation mutationObject =
            MutationPool.addMutation(
                className,
                methodName,
                "ReplaceComparisonOperator " + getOp(node.getOpcode()) + " -> " + getOp(op),
                instruction,
                mutation,
                getInfectionDistance(node.getOpcode(), op));
        mutations.add(mutationObject);
      } else {
        // Replace relational operator with TRUE/FALSE

        InsnList mutation = new InsnList();
        if (opcodesInt.contains(node.getOpcode())) mutation.add(new InsnNode(Opcodes.POP));
        else mutation.add(new InsnNode(Opcodes.POP2));
        if (op == TRUE) {
          mutation.add(new LdcInsnNode(1));
        } else {
          mutation.add(new LdcInsnNode(0));
        }
        mutation.add(new JumpInsnNode(Opcodes.IFNE, target));
        Mutation mutationObject =
            MutationPool.addMutation(
                className,
                methodName,
                "ReplaceComparisonOperator " + getOp(node.getOpcode()) + " -> " + op,
                instruction,
                mutation,
                getInfectionDistance(node.getOpcode(), op));
        mutations.add(mutationObject);
      }
    }

    return mutations;
  }
  public void addTinkersDrawHoveringTextHook(
      MethodNode method,
      Class<?> hookClass,
      String hookMethod,
      String hookDesc,
      boolean isObfuscated) {
    AbstractInsnNode targetNode = null;

    // get last drawGradientRect call
    for (AbstractInsnNode instruction : method.instructions.toArray()) {
      if (instruction.getOpcode() == INVOKEVIRTUAL) {
        MethodInsnNode methodInsn = (MethodInsnNode) instruction;

        if (methodInsn.desc.equals("(IIIIII)V")) targetNode = instruction;
      }
    }
    if (targetNode == null) {
      AppleCore.Log.warn("Could not patch " + method.name + "; target node not found");
      return;
    }

    LocalVariableNode x = ASMHelper.findLocalVariableOfMethod(method, "i1", "I");
    LocalVariableNode y = ASMHelper.findLocalVariableOfMethod(method, "j1", "I");
    LocalVariableNode w = ASMHelper.findLocalVariableOfMethod(method, "k", "I");
    LocalVariableNode h = ASMHelper.findLocalVariableOfMethod(method, "k1", "I");

    if (x == null || y == null || w == null || h == null) {
      AppleCore.Log.warn("Could not patch " + method.name + "; local variables not found");
      return;
    }

    InsnList toInject = new InsnList();

    /*
    // equivalent to:
    Hooks.onDrawHoveringText(0, 0, 0, 0);
    */

    toInject.add(new VarInsnNode(ILOAD, x.index));
    toInject.add(new VarInsnNode(ILOAD, y.index));
    toInject.add(new VarInsnNode(ILOAD, w.index));
    toInject.add(new VarInsnNode(ILOAD, h.index));
    toInject.add(
        new MethodInsnNode(
            INVOKESTATIC, hookClass.getName().replace('.', '/'), hookMethod, hookDesc, false));

    method.instructions.insert(targetNode, toInject);
  }
 private InsnList generateInvokeDynamicStatic(String name, String owner, String desc) {
   InsnList insnList = new InsnList();
   Handle methodHandle =
       new Handle(Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, "dynvokeStatic", BOOTSTRAP_SIGNATURE);
   insnList.add(new InvokeDynamicInsnNode(owner + "." + name, desc, methodHandle, ""));
   return insnList;
 }
Beispiel #10
0
 public static InsnList createArgumentLoaders(String methodDescriptor) {
   checkArgNotNull(methodDescriptor, "methodDescriptor");
   InsnList instructions = new InsnList();
   Type[] types = Type.getArgumentTypes(methodDescriptor);
   for (int i = 0; i < types.length; i++) {
     instructions.add(new VarInsnNode(getLoadingOpcode(types[i]), i + 1));
   }
   return instructions;
 }
Beispiel #11
0
  /**
   * getInfectionDistance
   *
   * @param original a {@link org.objectweb.asm.tree.FieldInsnNode} object.
   * @param mutant a {@link org.objectweb.asm.tree.InsnList} object.
   * @return a {@link org.objectweb.asm.tree.InsnList} object.
   */
  public InsnList getInfectionDistance(FieldInsnNode original, InsnList mutant) {
    InsnList distance = new InsnList();

    if (original.getOpcode() == Opcodes.GETFIELD)
      distance.add(new InsnNode(Opcodes.DUP)); // make sure to re-load this for GETFIELD

    distance.add(
        new FieldInsnNode(original.getOpcode(), original.owner, original.name, original.desc));
    Type type = Type.getType(original.desc);

    if (type.getDescriptor().startsWith("L") || type.getDescriptor().startsWith("[")) {
      ReplaceVariable.addReferenceDistanceCheck(distance, type, mutant);
    } else {
      ReplaceVariable.addPrimitiveDistanceCheck(distance, type, mutant);
    }

    return distance;
  }
 private InsnList generateInvokeDynamicConstructor(String name, String owner, String desc) {
   InsnList insnList = new InsnList();
   Handle methodHandle =
       new Handle(
           Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, "dynvokeConstructor", BOOTSTRAP_SIGNATURE);
   String descReceiver =
       Type.getMethodDescriptor(Type.getObjectType(owner), Type.getArgumentTypes(desc));
   insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, ""));
   return insnList;
 }
  private byte[] transformEntitySheep(byte[] bytes) {
    System.out.println("Transforming EntitySheep...");
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);

    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();

      if (m.name.equals(names.get("entitySheep_setColour_func"))
          && m.desc.equals(names.get("entitySheep_setColour_desc"))) {
        System.out.println("Found target method: " + m.name + m.desc + "! Inserting call...");

        for (int idx = 0; idx < m.instructions.size(); idx++) {
          if (m.instructions.get(idx).getOpcode() == Opcodes.ISTORE) {
            System.out.println("Found ISTORE at index " + idx + ", inserting code afterwards...");
            idx++; // AFTERwards, not before ;)

            InsnList toAdd = new InsnList();

            // to mark the end of the code
            LabelNode lmmnode = new LabelNode(new Label());
            // load this
            toAdd.add(new VarInsnNode(Opcodes.ALOAD, 0));
            // new fleece colour
            toAdd.add(new VarInsnNode(Opcodes.ILOAD, 1));
            // old fleece colour
            toAdd.add(new VarInsnNode(Opcodes.ILOAD, 2));
            toAdd.add(
                new MethodInsnNode(
                    Opcodes.INVOKESTATIC,
                    "keepcalm/mods/events/ForgeEventHelper",
                    "onSheepDye",
                    "(L" + names.get("entitySheep_javaName") + ";II)Z"));
            LabelNode endIf = new LabelNode(new Label());
            toAdd.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
            toAdd.add(new InsnNode(Opcodes.RETURN));
            toAdd.add(endIf);
            toAdd.add(lmmnode);

            m.instructions.insertBefore(m.instructions.get(idx), toAdd);
            break;
          }
        }
      }
    }

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
  public void addCodeChickenDrawHoveringTextHook(
      MethodNode method, Class<?> hookClass, String hookMethod, String hookDesc) {
    AbstractInsnNode targetNode = ASMHelper.findFirstInstruction(method);

    InsnList toInject = new InsnList();

    /*
    // equivalent to:
    Hooks.onDrawHoveringText(0, 0, 0, 0);
    */

    toInject.add(new VarInsnNode(ILOAD, 0)); // x
    toInject.add(new VarInsnNode(ILOAD, 1)); // y
    toInject.add(new VarInsnNode(ILOAD, 2)); // w
    toInject.add(new VarInsnNode(ILOAD, 3)); // h
    toInject.add(
        new MethodInsnNode(
            INVOKESTATIC, hookClass.getName().replace('.', '/'), hookMethod, hookDesc, false));

    method.instructions.insertBefore(targetNode, toInject);
  }
  private void addInitializationLogicToConstructors() {
    if (!classMetadata.hasManagedFieldsWithFieldGranularity()) {
      return;
    }

    for (MethodNode methodNode : (List<MethodNode>) classNode.methods) {
      MethodMetadata methodMetadata =
          classMetadata.getMethodMetadata(methodNode.name, methodNode.desc);

      if (methodMetadata.isTransactional() && methodMetadata.isConstructor()) {
        int firstAfterSuper = firstIndexAfterSuper(methodNode, classNode.superName);

        if (firstAfterSuper >= 0) {
          InsnList extraInstructions = new InsnList();
          for (FieldNode fieldNode : (List<FieldNode>) classNode.fields) {
            FieldMetadata fieldMetadata = classMetadata.getFieldMetadata(fieldNode.name);

            if (fieldMetadata.hasFieldGranularity()) {
              extraInstructions.add(new VarInsnNode(ALOAD, 0));

              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              extraInstructions.add(new TypeInsnNode(NEW, referenceName));
              extraInstructions.add(new InsnNode(DUP));

              extraInstructions.add(
                  new MethodInsnNode(INVOKESPECIAL, referenceName, "<init>", "()V"));

              extraInstructions.add(
                  new FieldInsnNode(PUTFIELD, classNode.name, fieldNode.name, referenceDesc));
            }

            AbstractInsnNode first = methodNode.instructions.get(firstAfterSuper);
            methodNode.instructions.insert(first, extraInstructions);
          }
        }
      }
    }
  }
  /**
   * getInfectionDistance
   *
   * @param opcodeOrig a int.
   * @param opcodeNew a int.
   * @return a {@link org.objectweb.asm.tree.InsnList} object.
   */
  public InsnList getInfectionDistance(int opcodeOrig, int opcodeNew) {
    InsnList distance = new InsnList();
    switch (opcodeOrig) {
      case Opcodes.IF_ICMPEQ:
      case Opcodes.IF_ICMPNE:
      case Opcodes.IF_ICMPLE:
      case Opcodes.IF_ICMPLT:
      case Opcodes.IF_ICMPGE:
      case Opcodes.IF_ICMPGT:
        distance.add(new InsnNode(Opcodes.DUP2));
        distance.add(new LdcInsnNode(opcodeOrig));
        distance.add(new LdcInsnNode(opcodeNew));
        distance.add(
            new MethodInsnNode(
                Opcodes.INVOKESTATIC,
                "org/evosuite/instrumentation/mutation/ReplaceComparisonOperator",
                "getInfectionDistance",
                "(IIII)D",
                false));
        break;

      case Opcodes.IFEQ:
      case Opcodes.IFNE:
      case Opcodes.IFLE:
      case Opcodes.IFLT:
      case Opcodes.IFGE:
      case Opcodes.IFGT:
        distance.add(new InsnNode(Opcodes.DUP));
        distance.add(new LdcInsnNode(opcodeOrig));
        distance.add(new LdcInsnNode(opcodeNew));
        distance.add(
            new MethodInsnNode(
                Opcodes.INVOKESTATIC,
                "org/evosuite/instrumentation/mutation/ReplaceComparisonOperator",
                "getInfectionDistance",
                "(III)D",
                false));
        break;

      default:
        distance.add(new LdcInsnNode(0.0));
    }

    return distance;
  }
 @Override
 protected void apply(ClassNode cn) {
   MethodNode m =
       ReikaASMHelper.getMethodByName(
           cn,
           "func_77943_a",
           "tryPlaceItemIntoWorld",
           "(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;IIIIFFF)Z");
   AbstractInsnNode ain = ReikaASMHelper.getLastOpcode(m.instructions, Opcodes.INVOKEVIRTUAL);
   InsnList li = new InsnList();
   li.add(new VarInsnNode(Opcodes.ALOAD, 0));
   li.add(new VarInsnNode(Opcodes.ALOAD, 1));
   li.add(new VarInsnNode(Opcodes.ALOAD, 2));
   li.add(new VarInsnNode(Opcodes.ILOAD, 3));
   li.add(new VarInsnNode(Opcodes.ILOAD, 4));
   li.add(new VarInsnNode(Opcodes.ILOAD, 5));
   li.add(new VarInsnNode(Opcodes.ILOAD, 6));
   li.add(new VarInsnNode(Opcodes.FLOAD, 7));
   li.add(new VarInsnNode(Opcodes.FLOAD, 8));
   li.add(new VarInsnNode(Opcodes.FLOAD, 9));
   li.add(
       new MethodInsnNode(
           Opcodes.INVOKESTATIC,
           "Reika/DragonAPI/Instantiable/Event/PostItemUseEvent",
           "fire",
           "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/world/World;IIIIFFF)V",
           false));
   m.instructions.insert(ain, li);
   // ReikaJavaLibrary.pConsole(ReikaASMHelper.clearString(m.instructions));
 }
 private InsnList generateInvokeDynamicVirtualInterfaceSpecial(
     String name, String owner, String desc, String bootstrapMethod) {
   InsnList insnList = new InsnList();
   Handle methodHandle =
       new Handle(Opcodes.H_INVOKESTATIC, BOOTSTRAP_CLASS, bootstrapMethod, BOOTSTRAP_SIGNATURE);
   List<Type> argsList =
       new ArrayList<Type>(Arrays.asList(new Type[] {Type.getObjectType(owner)}));
   argsList.addAll(Arrays.asList(Type.getArgumentTypes(desc)));
   String descReceiver =
       Type.getMethodDescriptor(
           Type.getReturnType(desc), argsList.toArray(new Type[argsList.size()]));
   insnList.add(new InvokeDynamicInsnNode(owner + "." + name, descReceiver, methodHandle, ""));
   return insnList;
 }
  public byte[] transformCreeper(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);

    // System.out.println("Transforming EntityCreeper...");

    Iterator<MethodNode> methods = cn.methods.iterator();

    while (methods.hasNext()) {
      MethodNode m = methods.next();

      // System.out.println(m.name + m.desc + " vs " + names.get("entityCreeper_onUpdate_func") +
      // names.get("entityCreeper_onUpdate_desc"));
      if (m.name.equals(names.get("entityCreeper_onUpdate_func"))
          && m.desc.equals(names.get("entityCreeper_onUpdate_desc"))) {
        for (int i = m.instructions.size() - 1; i >= 0; i--) {
          if (m.instructions.get(i).getOpcode() == Opcodes.IFNE) {
            System.out.println("Found insertion point! inserting code!");
            i++;

            InsnList insns = new InsnList();

            insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
            insns.add(
                new MethodInsnNode(
                    Opcodes.INVOKESTATIC,
                    "keepcalm/mods/events/ForgeEventHelper",
                    "onCreeperExplode",
                    "(L" + names.get("entityCreeper_javaName") + ";)Z"));
            LabelNode endIf = new LabelNode(new Label());
            insns.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
            // insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
            // insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
            // names.get("entityCreeper_javaName"), names.get("entityCreeper_setDead_func"),
            // names.get("entityCreeper_setDead_desc")));
            insns.add(new InsnNode(Opcodes.RETURN));
            insns.add(endIf);
            insns.add(new LabelNode(new Label()));

            m.instructions.insertBefore(m.instructions.get(i), insns);
            break;
          }
        }
      }
    }
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
  public void addPeacefulRegenHook(ClassNode classNode, MethodNode method) {
    AbstractInsnNode relevantConditional =
        ASMHelper.find(method.instructions, new LdcInsnNode("naturalRegeneration"));
    JumpInsnNode ifNode =
        (JumpInsnNode) ASMHelper.find(relevantConditional, new JumpInsnNode(IFEQ, new LabelNode()));
    LabelNode ifBlockEndLabel = ifNode.label;
    AbstractInsnNode targetNode = ASMHelper.find(ifNode, new InsnNode(FCONST_1)).getPrevious();

    int peacefulRegenEventIndex =
        firePeacefulRegenEventAndStoreEventBefore(method, targetNode, ifBlockEndLabel);

    InsnList healAmountNeedle = new InsnList();
    healAmountNeedle.add(new InsnNode(FCONST_1));

    InsnList healAmountReplacement = new InsnList();
    healAmountReplacement.add(new VarInsnNode(ALOAD, peacefulRegenEventIndex));
    healAmountReplacement.add(
        new FieldInsnNode(
            GETFIELD,
            Type.getInternalName(HealthRegenEvent.PeacefulRegen.class),
            "deltaHealth",
            "F"));

    ASMHelper.findAndReplace(
        method.instructions, healAmountNeedle, healAmountReplacement, targetNode);

    InsnList ifNotCanceledBlock = new InsnList();
    LabelNode ifNotCanceled = new LabelNode();

    ifNotCanceledBlock.add(new VarInsnNode(ALOAD, peacefulRegenEventIndex));
    ifNotCanceledBlock.add(
        new MethodInsnNode(
            INVOKEVIRTUAL,
            Type.getInternalName(HealthRegenEvent.PeacefulRegen.class),
            "isCanceled",
            "()Z",
            false));
    ifNotCanceledBlock.add(new JumpInsnNode(IFNE, ifNotCanceled));
    method.instructions.insertBefore(targetNode, ifNotCanceledBlock);

    method.instructions.insertBefore(ifBlockEndLabel, ifNotCanceled);
  }
  private byte[] transformNetServerHandler(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);

    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();

      if (m.name.equals(names.get("netServerHandler_handleFlying_func"))
          && m.desc.equals(names.get("netServerHandler_handleFlying_desc"))) {
        System.out.println("Found target method: " + m.name + m.desc + "! Inserting code...");

        InsnList toInsert = new InsnList();
        toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1));
        toInsert.add(new VarInsnNode(Opcodes.ALOAD, 0));
        toInsert.add(
            new MethodInsnNode(
                Opcodes.INVOKESTATIC,
                "keepcalm/mods/events/ForgeEventHelper",
                "onPlayerMove",
                "(L"
                    + names.get("packet10Flying_javaName")
                    + ";L"
                    + names.get("netServerHandler_javaName")
                    + ";)Z"));
        LabelNode endIf = new LabelNode(new Label());
        toInsert.add(new JumpInsnNode(Opcodes.IFEQ, endIf));
        toInsert.add(new InsnNode(Opcodes.RETURN));
        toInsert.add(endIf);
        toInsert.add(new LabelNode(new Label()));
        m.instructions.insert(toInsert);
      }
    }

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }
  private InsnList fixInstructions(MethodNode originalMethod, CloneMap cloneMap) {
    InsnList instructions = new InsnList();

    for (int k = 0; k < originalMethod.instructions.size(); k++) {
      AbstractInsnNode originalInsn = originalMethod.instructions.get(k);
      switch (originalInsn.getOpcode()) {
          // the put on the field granular field is transformed to a fieldref.set
        case PUTFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            ClassMetadata ownerMetadata =
                metadataRepository.loadClassMetadata(classLoader, fieldInsn.owner);
            FieldMetadata fieldMetadata = ownerMetadata.getFieldMetadata(fieldInsn.name);
            Type originalFieldType = Type.getType(fieldMetadata.getDesc());

            if (fieldMetadata.hasFieldGranularity()) {

              boolean fieldIsCategory2 = isCategory2(fieldMetadata.getDesc());

              if (fieldIsCategory2) {
                // value(category2), owner,..

                instructions.add(new InsnNode(DUP2_X1));
                // [value(category2), owner, value(category2),...]

                instructions.add(new InsnNode(POP2));
                // [owner, value(category2), ...]
              } else {
                // [value(category1), owner,
                instructions.add(new InsnNode(SWAP));
                // [owner, value(category1),..
              }

              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              if (fieldIsCategory2) {
                // [owner, value(category2),..

                instructions.add(new InsnNode(DUP_X2));
                // [owner, value(category2), owner

                instructions.add(new InsnNode(POP));
                // [value(category2), owner
              } else {
                // [owner, value(category1)
                instructions.add(new InsnNode(SWAP));
                // [value(category1), owner..
              }

              // call the set
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                String objectDesc = Type.getDescriptor(Object.class);
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", objectDesc, objectDesc));
                instructions.add(methodInsn);
              } else {
                MethodInsnNode methodInsn =
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "set",
                        format("(%s)%s", fieldMetadata.getDesc(), fieldMetadata.getDesc()));
                instructions.add(methodInsn);
              }

              // pop the unused return value of the set.
              if (fieldIsCategory2) {
                instructions.add(new InsnNode(POP2));
              } else {
                instructions.add(new InsnNode(POP));
              }
            } else {
              instructions.add(originalInsn.clone(cloneMap));
            }
          }
          break;
          // the get on the field granular field is transformed to a fieldref.get
        case GETFIELD:
          {
            FieldInsnNode fieldInsn = (FieldInsnNode) originalInsn;
            FieldMetadata fieldMetadata =
                metadataRepository
                    .loadClassMetadata(classLoader, fieldInsn.owner)
                    .getFieldMetadata(fieldInsn.name);
            if (!fieldMetadata.hasFieldGranularity()) {
              // if it is not getter on a field granular field
              instructions.add(originalInsn.clone(cloneMap));
            } else {
              // it is a getter on a field granular field.
              String referenceDesc = findReferenceDesc(fieldMetadata.getDesc());
              String referenceName = Type.getType(referenceDesc).getInternalName();

              // place the fieldref on the stack.
              instructions.add(
                  new FieldInsnNode(GETFIELD, fieldInsn.owner, fieldInsn.name, referenceDesc));

              Type originalFieldType = Type.getType(fieldMetadata.getDesc());
              if (originalFieldType.getSort() == Type.ARRAY
                  || originalFieldType.getSort() == Type.OBJECT) {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", getDescriptor(Object.class))));

                if (!originalFieldType.equals(Type.getType(Object.class))) {
                  instructions.add(
                      new TypeInsnNode(CHECKCAST, originalFieldType.getInternalName()));
                }
              } else {
                instructions.add(
                    new MethodInsnNode(
                        INVOKEVIRTUAL,
                        referenceName,
                        "get",
                        format("()%s", fieldMetadata.getDesc())));
              }
            }
          }
          break;
        default:
          instructions.add(originalInsn.clone(cloneMap));
          break;
      }
    }

    return instructions;
  }
  @Override
  boolean processMethods(List<MethodNode> methods) {
    int found = 0;
    for (MethodNode mn : methods) {
      if (mn.name.equals("<init>")) {
        logger.log(Level.INFO, "\tPatching constructor in EntityPlayer");
        ListIterator<AbstractInsnNode> it = mn.instructions.iterator();

        while (it.hasNext()) {
          AbstractInsnNode insn = it.next();
          if (insn instanceof TypeInsnNode) {
            if (((TypeInsnNode) insn).desc.equals(inventoryClassName)) {
              ((TypeInsnNode) insn).desc = "mods/battlegear2/api/core/InventoryPlayerBattle";
            }

          } else if (insn instanceof MethodInsnNode) {
            if (((MethodInsnNode) insn).owner.equals(inventoryClassName)) {
              ((MethodInsnNode) insn).owner = "mods/battlegear2/api/core/InventoryPlayerBattle";
            }
          }
        }
        found++;
      } else if (mn.name.equals(onItemFinishMethodName) && mn.desc.equals(SIMPLEST_METHOD_DESC)) {
        sendPatchLog("onItemUseFinish");
        InsnList newList = new InsnList();
        ListIterator<AbstractInsnNode> it = mn.instructions.iterator();
        while (it.hasNext()) {
          AbstractInsnNode next = it.next();
          if (next instanceof MethodInsnNode
              && ((MethodInsnNode) next)
                  .owner.equals("net/minecraftforge/event/ForgeEventFactory")) {
            found++;
            int index = ((MethodInsnNode) next).desc.indexOf(")");
            String newDesc =
                ((MethodInsnNode) next).desc.substring(0, index)
                    + "I"
                    + ((MethodInsnNode) next).desc.substring(index);
            newList.add(new VarInsnNode(ILOAD, 1));
            newList.add(
                new MethodInsnNode(INVOKESTATIC, UTILITY_CLASS, "beforeFinishUseEvent", newDesc));
          } else {
            newList.add(next);
          }
        }
        mn.instructions = newList;
      } else if (mn.name.equals(onUpdateMethodName) && mn.desc.equals(SIMPLEST_METHOD_DESC)) {
        sendPatchLog("onUpdate");
        InsnList newList = new InsnList();
        ListIterator<AbstractInsnNode> it = mn.instructions.iterator();
        while (it.hasNext()) {
          AbstractInsnNode next = it.next();
          if (next instanceof FieldInsnNode
              && ((FieldInsnNode) next).owner.equals(entityPlayerClassName)
              && ((FieldInsnNode) next).name.equals(playerInventoryFieldName)) {
            found++;
            newList.add(new VarInsnNode(ALOAD, 0));
            newList.add(
                new FieldInsnNode(
                    GETFIELD,
                    entityPlayerClassName,
                    playerItemInUseField,
                    "L" + itemStackClassName + ";"));
            newList.add(
                new MethodInsnNode(
                    INVOKESTATIC,
                    UTILITY_CLASS,
                    "getCurrentItemOnUpdate",
                    "(L"
                        + entityPlayerClassName
                        + ";L"
                        + itemStackClassName
                        + ";)L"
                        + itemStackClassName
                        + ";"));
            next = it.next();
          } else {
            newList.add(next);
          }
        }
        mn.instructions = newList;
      } else if (mn.name.equals(setCurrentItemArmourMethodName)
          && mn.desc.equals(setCurrentItemArmourMethodDesc)) {

        sendPatchLog("setCurrentItemOrArmor");
        replaceInventoryArrayAccess(
            mn, entityPlayerClassName, playerInventoryFieldName, mn.maxStack, mn.maxLocals);
        found++;
      } else if (mn.name.equals(interactWithMethodName) && mn.desc.equals(interactWithMethodDesc)) {
        sendPatchLog("interactWith");
        MethodNode mv =
            new MethodNode(ACC_PUBLIC, interactWithMethodName, interactWithMethodDesc, null, null);
        mv.visitCode();
        Label l0 = new Label();
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKESTATIC,
            UTILITY_CLASS,
            "interactWith",
            "(L" + entityPlayerClassName + ";L" + entityClassName + ";)Z");
        mv.visitInsn(IRETURN);
        Label l1 = new Label();
        mv.visitLabel(l1);
        mv.visitLocalVariable("this", "L" + entityPlayerClassName + ";", null, l0, l1, 0);
        mv.visitLocalVariable("p_70998_1_", "L" + entityClassName + ";", null, l0, l1, 1);
        mv.visitMaxs(2, 2);
        mv.visitEnd();
        mn.instructions = mv.instructions;
        found++;
      }
    }

    logger.log(Level.INFO, "\tCreating new methods in EntityPlayer");
    methods.add(methods.size(), generateAttackOffhandMethod());
    methods.add(methods.size(), generateSwingOffhand());
    methods.add(methods.size(), generateGetOffSwingMethod());
    methods.add(methods.size(), generateUpdateSwingArm());
    methods.add(methods.size(), generateIsBattleMode());
    methods.add(methods.size(), generateIsBlockingWithShield());
    methods.add(methods.size(), generateSetBlockingWithShield());
    methods.add(
        methods.size(),
        generateGetter(entityPlayerClassName, "getSpecialActionTimer", "specialActionTimer", "I"));
    methods.add(
        methods.size(),
        generateSetter(entityPlayerClassName, "setSpecialActionTimer", "specialActionTimer", "I"));
    return found == 5;
  }
  private static void transformBiblioFramingChest(ClassNode classNode, boolean isObfuscated) {
    LOG.info("Found class. Hunting for method.");
    final String ENTITY_COLLIDE = "func_145845_h";
    final String ENTITY_COLLIDE_DESC = "()V";

    /* Instructions we need to find:
    mv.visitInsn(IADD);
    mv.visitFieldInsn(PUTFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "ticksSinceSync", "I");
    */

    /*	Need to add this: To tick the chest for heat and decay
    		mv.visitVarInsn(ALOAD, 0);
    		mv.visitVarInsn(ALOAD, 0);
    		mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "worldObj", "Lnet/minecraft/world/World;");
    		mv.visitVarInsn(ALOAD, 0);
    		mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "xCoord", "I");
    		mv.visitVarInsn(ALOAD, 0);
    		mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "yCoord", "I");
    		mv.visitVarInsn(ALOAD, 0);
    		mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "zCoord", "I");
    		mv.visitMethodInsn(INVOKESTATIC, "com/bioxx/tfc/Core/TFC_Core", "handleItemTicking", "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;III)V", false);
    */
    for (MethodNode method : classNode.methods) {

      if (method.name.equals(ENTITY_COLLIDE) && method.desc.equals(ENTITY_COLLIDE_DESC)) {
        LOG.info("Found our method");
        AbstractInsnNode targetNode = null;
        for (AbstractInsnNode instruction : method.instructions.toArray()) {
          if (instruction.getOpcode() == ALOAD) {
            if (((VarInsnNode) instruction).var == 0
                && instruction.getNext().getOpcode() == INVOKESPECIAL) {
              targetNode = instruction;
              LOG.info("Found target instruction");
              break;
            }
          }
        }
        if (targetNode != null) {
          /*
          mv.visitVarInsn(ALOAD, 0);
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "worldObj", "Lnet/minecraft/world/World;");
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "xCoord", "I");
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "yCoord", "I");
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "zCoord", "I");
          mv.visitVarInsn(ALOAD, 0);
          mv.visitFieldInsn(GETFIELD, "jds/bibliocraft/tileentities/TileEntityFramedChest", "ticksSinceSync", "I");
          mv.visitMethodInsn(INVOKESTATIC, "TechNodefirmacraft/ASM/Transform/TF_BiblioFramingChest", "handleItemTicking", "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;IIII)V", false);
                    	 */

          InsnList toInsert = new InsnList();
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(
              new FieldInsnNode(
                  GETFIELD,
                  "jds/bibliocraft/tileentities/TileEntityFramedChest",
                  "field_145850_b",
                  "Lnet/minecraft/world/World;"));
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(
              new FieldInsnNode(
                  GETFIELD,
                  "jds/bibliocraft/tileentities/TileEntityFramedChest",
                  "field_145851_c",
                  "I"));
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(
              new FieldInsnNode(
                  GETFIELD,
                  "jds/bibliocraft/tileentities/TileEntityFramedChest",
                  "field_145848_d",
                  "I"));
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(
              new FieldInsnNode(
                  GETFIELD,
                  "jds/bibliocraft/tileentities/TileEntityFramedChest",
                  "field_145849_e",
                  "I"));
          toInsert.add(new VarInsnNode(ALOAD, 0));
          toInsert.add(
              new FieldInsnNode(
                  GETFIELD,
                  "jds/bibliocraft/tileentities/TileEntityFramedChest",
                  "ticksSinceSync",
                  "I"));
          toInsert.add(
              new MethodInsnNode(
                  Opcodes.INVOKESTATIC,
                  "TechNodefirmacraft/ASM/Transform/TF_BiblioFramingChest",
                  "handleItemTicking",
                  "(Lnet/minecraft/inventory/IInventory;Lnet/minecraft/world/World;IIII)V",
                  false));
          method.instructions.insertBefore(targetNode, toInsert);
          LOG.info("Done terrible things to that method. Working?");

          // method.instructions.insert(popNode, newLabelNode);
        } else {
          LOG.error("Something went wrong transforming TileEntityFramedChest!");
        }
      }
    }
  }
  // 下記の想定で実装されています。
  // EntityLiving.class の doRenderLiving の先頭に
  // tutorial/test.class の passTestRender(EntityLiving, double, double, double)メソッドの呼び出しを追加する。
  private byte[] hookOnItemRightClick(String className, byte[] bytes) {
    // ASMで、bytesに格納されたクラスファイルを解析します。
    ClassNode cnode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(cnode, 0);

    // 改変対象のメソッド名です
    String targetMethodName = "onItemRightClick";
    String targetMethodNameSRG = "func_77659_a";

    // 改変対象メソッドの戻り値型および、引数型をあらわします ※1
    String targetMethoddesc =
        "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;";
    String targetMethoddescSRG =
        "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;)Lnet/minecraft/item/ItemStack;";

    // 対象のメソッドを検索取得します。
    MethodNode mnode = null;

    String mdesc = null;

    for (MethodNode curMnode : cnode.methods) {

      String mName =
          FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(className, curMnode.name, curMnode.desc);
      String mdName = FMLDeobfuscatingRemapper.INSTANCE.mapMethodDesc(curMnode.desc);
      // System.out.println("[ " + mName + " : " + curMnode.name + " ]  [ " + mdName + " : " +
      // curMnode.desc);
      if ((targetMethodName.equals(curMnode.name) && targetMethoddesc.equals(curMnode.desc))
          || (targetMethodNameSRG.equals(mName) && targetMethoddescSRG.equals(mdName))) {
        mnode = curMnode;
        mdesc = curMnode.desc;
        break;
      }
    }

    if (mnode != null) {

      InsnList overrideList = new InsnList();

      // メソッドコールを、バイトコードであらわした例です。

      overrideList.add(new VarInsnNode(ALOAD, 1));
      overrideList.add(new VarInsnNode(ALOAD, 2));
      overrideList.add(new VarInsnNode(ALOAD, 3));
      overrideList.add(
          new MethodInsnNode(
              INVOKESTATIC,
              "shift/sextiarysector/asm/vanilla/BottleMethod",
              "onBottleRightClick",
              mdesc,
              false));
      overrideList.add(new InsnNode(ARETURN));

      // mnode.instructions.get(1)で、対象のメソッドの先頭を取得
      // mnode.instructions.insertで、指定した位置にバイトコードを挿入します。
      mnode.instructions.insert(mnode.instructions.get(1), overrideList);

      // mnode.maxLocals = 4;

      // 改変したクラスファイルをバイト列に書き出します
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
      cnode.accept(cw);
      bytes = cw.toByteArray();

      System.out.println("bbbb");
    }

    return bytes;
  }
  private byte[] transformLightningBolt(byte[] bytes) {
    ClassNode cn = new ClassNode();
    ClassReader cr = new ClassReader(bytes);
    cr.accept(cn, 0);

    Iterator<MethodNode> methods = cn.methods.iterator();
    while (methods.hasNext()) {
      MethodNode m = methods.next();
      if (m.name.equals("<init>")) {
        System.out.println("Found constructor in EntityLightningBolt, searching for landmarks...");
        AbstractInsnNode mark1 = null;
        AbstractInsnNode mark2 = null;
        AbstractInsnNode firstEndIf = null;
        AbstractInsnNode secondEndIf = null;

        InsnList insns1 = new InsnList();
        insns1.add(new VarInsnNode(Opcodes.ALOAD, 0));
        insns1.add(new VarInsnNode(Opcodes.ALOAD, 1));
        insns1.add(new VarInsnNode(Opcodes.ILOAD, 8));
        insns1.add(new VarInsnNode(Opcodes.ILOAD, 9));
        insns1.add(new VarInsnNode(Opcodes.ILOAD, 10));
        insns1.add(
            new MethodInsnNode(
                Opcodes.INVOKESTATIC,
                "keepcalm/mods/events/ForgeEventHelper",
                "onLightningStrike",
                "(L"
                    + names.get("entityLightningBolt_javaName")
                    + ";L"
                    + names.get("world_javaName")
                    + ";III)Z"));
        LabelNode endIf1 = new LabelNode(new Label());
        insns1.add(new JumpInsnNode(Opcodes.IFNE, endIf1));

        InsnList insns2 = new InsnList();
        insns1.add(new InsnNode(Opcodes.ACONST_NULL));
        insns2.add(new VarInsnNode(Opcodes.ALOAD, 1));
        insns2.add(new VarInsnNode(Opcodes.ILOAD, 9));
        insns2.add(new VarInsnNode(Opcodes.ILOAD, 10));
        insns2.add(new VarInsnNode(Opcodes.ILOAD, 11));
        insns2.add(
            new MethodInsnNode(
                Opcodes.INVOKESTATIC,
                "keepcalm/mods/events/ForgeEventHelper",
                "onLightningStrike",
                "(L"
                    + names.get("entityLightningBolt_javaName")
                    + ";L"
                    + names.get("world_javaName")
                    + ";III)Z"));
        LabelNode endIf2 = new LabelNode(new Label());
        insns2.add(new JumpInsnNode(Opcodes.IFNE, endIf2));
        boolean firstInvokeV = false;

        for (int i = 0; i < m.instructions.size(); i++) {

          if (m.instructions.get(i).getOpcode() == Opcodes.IFEQ) {
            if (mark1 != null) mark2 = m.instructions.get(i).getNext();
            else mark1 = m.instructions.get(i).getNext();
          }

          if (m.instructions.get(i).getOpcode() == Opcodes.INVOKEVIRTUAL
              && !firstInvokeV
              && mark1 != null) {
            firstEndIf = m.instructions.get(i).getNext();
          } else if (m.instructions.get(i).getOpcode() == Opcodes.INVOKEVIRTUAL
              && mark2 != null
              && firstInvokeV) {
            secondEndIf = m.instructions.get(i).getNext();
          }
        }
        m.instructions.insertBefore(mark1, insns1);
        m.instructions.insertBefore(firstEndIf, endIf1);
        m.instructions.insertBefore(mark2, insns2);
        m.instructions.insertBefore(secondEndIf, endIf2);
      }
    }

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    return cw.toByteArray();
  }