List of usage examples for org.objectweb.asm.tree InsnList InsnList
InsnList
From source file:pl.clareo.coroutines.core.MethodTransformer.java
License:Apache License
@SuppressWarnings("unchecked") MethodNode transform(String coroutineName, boolean generateDebugCode) { MethodNode transformedMethod = new MethodNode(); transformedMethod.access = ACC_PUBLIC | ACC_FINAL | (method.access & ACC_STATIC); transformedMethod.name = coroutineName; transformedMethod.desc = COROUTINE_METHOD_DESCRIPTOR; transformedMethod.exceptions = method.exceptions; final InsnList newCode = transformedMethod.instructions; Analyzer analyzer = new Analyzer(new BasicInterpreter() { @Override/*from w ww. ja v a 2 s .co m*/ public Value binaryOperation(AbstractInsnNode insn, Value value1, Value value2) throws AnalyzerException { if (insn.getOpcode() == AALOAD) { return new BasicValue(((BasicValue) value1).getType().getElementType()); } return super.binaryOperation(insn, value1, value2); }; @Override public Value merge(Value v, Value w) { if (v == NULL_VALUE) { BasicValue w1 = (BasicValue) w; if (w1.isReference()) { return w1; } } if (w == NULL_VALUE) { BasicValue v1 = (BasicValue) v; if (v1.isReference()) return v1; } if (!v.equals(w)) { BasicValue v1 = (BasicValue) v; BasicValue w1 = (BasicValue) w; if (v1.isReference() & w1.isReference()) { Class<?> c1; Class<?> c2; try { c1 = MethodTransformer.getClass(v1); c2 = MethodTransformer.getClass(w1); } catch (ClassNotFoundException e) { throw new CoroutineGenerationException( "It was needed to load a class during transformation process but loading unexpectedly failed", e); } if (c1.isAssignableFrom(c2)) { return v; } if (c2.isAssignableFrom(c1)) { return w; } } } else { return v; } return BasicValue.UNINITIALIZED_VALUE; } @Override public Value newValue(Type type) { if (type != null) { int typeSort = type.getSort(); switch (typeSort) { case Type.VOID: return NULL_VALUE; 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: if (type.getInternalName().equals("null")) { return NULL_VALUE; } return new BasicValue(type); default: throw new Error("Internal error"); } } return BasicValue.UNINITIALIZED_VALUE; } }); Frame[] frames; try { frames = analyzer.analyze(methodOwner, method); } catch (AnalyzerException e) { throw new CoroutineGenerationException(e); } InsnList code = method.instructions; final List<Integer> yields = new ArrayList<Integer>(8); /* * Copy instructions patching variable indexes and frames, remember * yield indexes */ int ic = 0; Iterator<AbstractInsnNode> i = code.iterator(); while (i.hasNext()) { AbstractInsnNode insn = i.next(); switch (insn.getType()) { case AbstractInsnNode.FRAME: FrameNode frame = (FrameNode) insn.clone(labelsMap); // update values if (frame.type == F_FULL) { if (isStatic) { frame.local.addAll(0, argsStackMapList); } else { frame.local.addAll(1, argsStackMapList); } } newCode.add(frame); break; case AbstractInsnNode.IINC_INSN: IincInsnNode iinc = (IincInsnNode) insn.clone(labelsMap); iinc.var += variableIndexOffset; newCode.add(iinc); break; case AbstractInsnNode.INSN: switch (insn.getOpcode()) { case DRETURN: case FRETURN: case IRETURN: case LRETURN: case ARETURN: case RETURN: newCode.add(new InsnNode(POP)); newCode.add(throwex("java/util/NoSuchElementException")); break; default: newCode.add(insn.clone(labelsMap)); } break; case AbstractInsnNode.JUMP_INSN: if (insn.getOpcode() == JSR) { throw new CoroutineGenerationException("<jsr> not allowed"); } JumpInsnNode jump = (JumpInsnNode) insn; LabelNode target = jump.label; if (!labelsMap.containsKey(target)) { labelsMap.put(target, new LabelNode()); } newCode.add(jump.clone(labelsMap)); break; case AbstractInsnNode.LABEL: if (!labelsMap.containsKey(insn)) { labelsMap.put((LabelNode) insn, new LabelNode()); } newCode.add(insn.clone(labelsMap)); break; case AbstractInsnNode.METHOD_INSN: if (insn.getOpcode() == INVOKESTATIC) { MethodInsnNode method = (MethodInsnNode) insn; if (method.owner.equals(COROUTINES_NAME)) { String methodName = method.name; if (methodName.equals("_")) { /* * a call to artificial CoIterator, since it is * not needed after instrumentation we replace * it with null. This null will be popped by * corresponding ARETURN. Stack is not changed */ newCode.add(new InsnNode(ACONST_NULL)); break; } if (methodName.equals("yield")) { /* * a call to yield - core of coroutine * processing */ yields.add(ic); } } } newCode.add(insn.clone(labelsMap)); break; case AbstractInsnNode.VAR_INSN: if (insn.getOpcode() == RET) { throw new CoroutineGenerationException("<ret> not allowed"); } VarInsnNode var = (VarInsnNode) insn.clone(labelsMap); if (var.var != 0 || isStatic) { var.var += variableIndexOffset; } newCode.add(var); break; default: newCode.add(insn.clone(labelsMap)); break; } ic += 1; } /* * patch yields in transformed code */ final List<LabelNode> gotos = new ArrayList<LabelNode>(9); final Set<TryCatchBlockNode> patchedTryCatchBlocks = new HashSet<TryCatchBlockNode>(); int yieldIndex = 0; i = newCode.iterator(); while (i.hasNext()) { AbstractInsnNode insn = i.next(); /* * track locals */ int insnType = insn.getType(); if (insnType == AbstractInsnNode.VAR_INSN) { int opcode = insn.getOpcode(); if (opcode == ASTORE || opcode == DSTORE || opcode == LSTORE || opcode == ISTORE || opcode == FSTORE) { int varIndex = ((VarInsnNode) insn).var - variableIndexOffset; finals[varIndex] = false; } continue; } /* * track line numbers */ if (insnType == AbstractInsnNode.LINE) { lineNumber = ((LineNumberNode) insn).line; continue; } if (insnType != AbstractInsnNode.METHOD_INSN) { continue; } MethodInsnNode method = (MethodInsnNode) insn; if (!method.owner.equals(COROUTINES_NAME) || !method.name.equals("yield")) { continue; } InsnList yieldCode = new InsnList(); int index = yields.get(yieldIndex); Frame f = frames[index]; /* * a) operand on the top of stack is passed to the caller, we will * save it in 'in' parameter OR there is nothing to be passed to the * caller in case of yield() overload */ boolean yieldWithArgument = Type.getArgumentTypes(method.desc).length != 0; boolean nonemptyStack; Type[] stackContents = null; int stackTop = 0; if (yieldWithArgument) { yieldCode.add(input(getStackTop(f))); nonemptyStack = f.getStackSize() > 1; stackTop = 1; } else { nonemptyStack = f.getStackSize() > 0; } /* * b) save remaining stack */ if (nonemptyStack) { stackContents = getStackContents(f); // sanitize stack for (Type t : stackContents) { if (t == null) { throw new CoroutineGenerationException( "It is not possible to yield with uninitialized memory on the stack. Probably you use construct such as: new A(..,yield,..). Please move this yield call out of constructor"); } } yieldCode.add(savestack(frame, stackContents, stackTop)); } /* * c) save locals and state */ Type[] locals = getLocals(f); yieldCode.add(saveLocals(locals)); yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(makeInt(++yieldIndex)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "setState", "(I)V")); /* * d) jump to exit - in debug mode save line number */ if (generateDebugCode) { yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(makeInt(lineNumber)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "setLineOfCode", "(I)V")); } yieldCode.add(new JumpInsnNode(GOTO, yieldLabel)); /* * e) fix jump from switch statement */ LabelNode jump = new LabelNode(); gotos.add(jump); yieldCode.add(jump); yieldCode.add(emitCleanFrame()); /* * f) check if exit condition occurs, load locals, restore stack and * stack map */ yieldCode.add(new VarInsnNode(ALOAD, frame)); yieldCode.add(new MethodInsnNode(INVOKEVIRTUAL, FRAME_NAME, "isCoroutineClosed", "()Z")); LabelNode continueHere = new LabelNode(); yieldCode.add(new JumpInsnNode(IFEQ, continueHere)); yieldCode.add(throwex(COROUTINE_EXIT_EXCEPTION)); yieldCode.add(continueHere); yieldCode.add(new FrameNode(F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); /* * find previous frame node, load locals then emit new frame node * and load rest */ FrameNode prevFrame = findPreviousFrame(code.get(index)); Type[] prevLocals; if (prevFrame != null) { Frame oldFrame = frames[code.indexOf(prevFrame)]; prevLocals = getLocals(oldFrame); } else { prevLocals = getLocals(frames[0]); } yieldCode.add(restoreLocals(prevLocals)); FrameNode frameNode = mergeFrames(getFrameTypes(prevLocals), null); if (frameNode.type != F_SAME) { // bug fix - when no locals are restored and the stack is empty // two frames are collapsed yieldCode.add(frameNode); } if (nonemptyStack) { yieldCode.add(loadstack(frame, stackContents, stackTop)); } // restore temp locals in scope yieldCode.add(restoreLocals(diff(locals, prevLocals))); /* * push "sent" value */ yieldCode.add(new VarInsnNode(ALOAD, out)); newCode.insertBefore(method, yieldCode); /* * patch try catch blocks */ List<TryCatchBlockNode> tryCatchBlocks = analyzer.getHandlers(index); if (tryCatchBlocks != null) { for (TryCatchBlockNode tryCatchBlock : tryCatchBlocks) { if (!patchedTryCatchBlocks.contains(tryCatchBlock)) { LabelNode handler = tryCatchBlock.handler; InsnList handlerPatch = new InsnList(); String exceptionType = tryCatchBlock.type == null ? "java/lang/Throwable" : tryCatchBlock.type; FrameNode catchFrame = emitCatchFrame(exceptionType); handlerPatch.add(catchFrame); Type[] ls = getLocals(frames[code.indexOf(handler)]); handlerPatch.add(restoreLocals(ls)); handlerPatch.add( mergeFrames(getFrameTypes(ls), new Type[] { Type.getObjectType(exceptionType) })); patchedTryCatchBlocks.add(tryCatchBlock); AbstractInsnNode newHandler = labelsMap.get(handler); // remove "real" frame since it is not needed now newCode.remove(findNextFrame(newHandler)); newCode.insert(newHandler, handlerPatch); } } } newCode.remove(method); } /* * copy local variables (wath out for indices change) and try catch * blocks to new method (clone) */ List<TryCatchBlockNode> tryCatchBlocks = method.tryCatchBlocks; if (!tryCatchBlocks.isEmpty()) { transformedMethod.tryCatchBlocks = new ArrayList<TryCatchBlockNode>(tryCatchBlocks.size()); for (TryCatchBlockNode tryCatchBlock : tryCatchBlocks) { transformedMethod.tryCatchBlocks.add( new TryCatchBlockNode(labelsMap.get(tryCatchBlock.start), labelsMap.get(tryCatchBlock.end), labelsMap.get(tryCatchBlock.handler), tryCatchBlock.type)); } } if (method.localVariables != null) { List<LocalVariableNode> localVariables = method.localVariables; List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>(localVariables.size()); for (LocalVariableNode localVariable : localVariables) { int newIndex = localVariable.index; if (newIndex != 0 || isStatic) { newIndex += variableIndexOffset; } newLocalVariables .add(new LocalVariableNode(localVariable.name, localVariable.desc, localVariable.signature, labelsMap.get(localVariable.start), labelsMap.get(localVariable.end), newIndex)); } transformedMethod.localVariables = newLocalVariables; } newCode.insert(codeBefore(gotos)); newCode.add(codeAfter()); return transformedMethod; }
From source file:portablejim.veinminer.asm.ItemInWorldManagerTransformer.java
License:Open Source License
private InsnList buildBlockIdFunctionCall(String obfuscatedClassName, String worldType, int blockVarIndex) { InsnList blockIdFunctionCall = new InsnList(); blockIdFunctionCall.add(new TypeInsnNode(Opcodes.NEW, blockIdClassName)); blockIdFunctionCall.add(new InsnNode(Opcodes.DUP)); blockIdFunctionCall.add(new VarInsnNode(Opcodes.ALOAD, 0)); blockIdFunctionCall.add(new FieldInsnNode(Opcodes.GETFIELD, obfuscatedClassName.replace(".", "/"), getCorrectName("theWorld"), typemap.get(getCorrectName("theWorld")))); blockIdFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 1)); blockIdFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 2)); blockIdFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 3)); blockIdFunctionCall.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, blockIdClassName, "<init>", String.format("(%sIII)V", worldType))); blockIdFunctionCall.add(new VarInsnNode(Opcodes.ASTORE, blockVarIndex)); return blockIdFunctionCall; }
From source file:portablejim.veinminer.asm.ItemInWorldManagerTransformer.java
License:Open Source License
private int insertCallAfterTryHarvestBlockFunction(MethodNode curMethod, String obfuscatedClassName, int startIndex) throws IndexOutOfBoundsException { LocalVariablesSorter varSorter = new LocalVariablesSorter(curMethod.access, curMethod.desc, curMethod); String worldType = typemap.get(getCorrectName("theWorld")); String playerType = typemap.get(getCorrectName("thisPlayerMP")); while (!isMethodWithName(curMethod.instructions.get(startIndex), "tryHarvestBlock")) { ++startIndex;// ww w . j av a2 s.com } do { --startIndex; } while (curMethod.instructions.get(startIndex).getType() == AbstractInsnNode.VAR_INSN); int blockVarIndex = varSorter.newLocal(Type.getType(BlockID.class)); curMethod.instructions.insert(curMethod.instructions.get(startIndex), buildBlockIdFunctionCall(obfuscatedClassName, worldType, blockVarIndex)); ++startIndex; while (!isMethodWithName(curMethod.instructions.get(startIndex), "tryHarvestBlock")) { ++startIndex; } // Add variable to store result int newVarIndex = varSorter.newLocal(Type.BOOLEAN_TYPE); VarInsnNode newVar = new VarInsnNode(Opcodes.ISTORE, newVarIndex); curMethod.instructions.insert(curMethod.instructions.get(startIndex), newVar); ++startIndex; // Add in function call to call function InsnList veinMinerFunctionCall = new InsnList(); veinMinerFunctionCall .add(new FieldInsnNode(Opcodes.GETSTATIC, targetClassName, "instance", targetClassType)); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ALOAD, 0)); veinMinerFunctionCall.add(new FieldInsnNode(Opcodes.GETFIELD, obfuscatedClassName.replace(".", "/"), getCorrectName("theWorld"), typemap.get(getCorrectName("theWorld")))); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ALOAD, 0)); veinMinerFunctionCall.add(new FieldInsnNode(Opcodes.GETFIELD, obfuscatedClassName.replace(".", "/"), getCorrectName("thisPlayerMP"), typemap.get(getCorrectName("thisPlayerMP")))); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 1)); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 2)); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, 3)); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ILOAD, newVarIndex)); veinMinerFunctionCall.add(new VarInsnNode(Opcodes.ALOAD, blockVarIndex)); String blockIdClassType = String.format("L%s;", blockIdClassName); veinMinerFunctionCall.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, targetClassName, targetMethodName, String.format(targetMethodType, worldType, playerType, blockIdClassType))); curMethod.instructions.insert(curMethod.instructions.get(startIndex), veinMinerFunctionCall); ++startIndex; // Get rid of un-needed POP. while (curMethod.instructions.get(startIndex).getOpcode() != Opcodes.POP) { ++startIndex; } curMethod.instructions.remove(curMethod.instructions.get(startIndex)); return startIndex; }
From source file:pxb.android.dex2jar.optimize.D.java
License:Apache License
/** * @param method// ww w. j a v a 2 s. co m */ @SuppressWarnings("rawtypes") private void rebuild(MethodNode method) { InsnList insnList = new InsnList(); method.instructions = insnList; List<LabelNode> visited = new ArrayList<LabelNode>(); Stack<Block> toWriteBlock = new Stack<Block>(); toWriteBlock.push(first); doRebuild(insnList, toWriteBlock, visited); method.tryCatchBlocks = new ArrayList(); for (Iterator<?> it = method.tryCatchBlocks.iterator(); it.hasNext();) { TryCatchBlockNode tcn = (TryCatchBlockNode) it.next(); toWriteBlock.push(map.get(tcn.handler)); doRebuild(insnList, toWriteBlock, visited); } }
From source file:rubah.bytecode.transformers.RedirectFieldManipulation.java
License:Open Source License
@Override public MethodVisitor visitMethod(int access, String name, final String desc, String signature, String[] exceptions) {/*from ww w. ja v a2s.c o m*/ final MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); if (this.namespace.isBootstrap(this.thisClass)) return methodVisitor; if (this.thisClass.getFqn().startsWith("java.io") || this.thisClass.getFqn().startsWith("sun.reflect") || this.thisClass.getFqn().startsWith("sun.misc") || this.thisClass.getFqn().startsWith("java.security") || this.thisClass.getFqn().startsWith("java.util.concurrent.locks") || this.thisClass.getFqn().startsWith("java.util.concurrent.atomic") || (this.thisClass.getFqn().startsWith("java.lang") && !this.thisClass.getFqn().equals(Class.class.getName()))) return methodVisitor; if (this.objectsMap != null) { Method m = (Method) objectsMap.get(name); if (m == null) return methodVisitor; if (m.getName().startsWith(AddGettersAndSetters.GETTER_PREFFIX) || m.getName().startsWith(AddGettersAndSetters.SETTER_PREFFIX)) return methodVisitor; } MethodVisitor ret = new MethodNode(ASM5, access, name, desc, signature, exceptions) { private Frame<SourceValue>[] sourcesFrames; private boolean isStatic = Modifier.isStatic(access); @Override public void visitEnd() { Analyzer<SourceValue> sourceAnalyzer = new Analyzer<SourceValue>(new SourceInterpreter()); try { sourceAnalyzer.analyze(thisClass.getASMType().getInternalName(), this); } catch (AnalyzerException e) { System.out.println(namespace.isBootstrap(thisClass)); System.out.println(e.getMessage()); this.sourcesFrames = sourceAnalyzer.getFrames(); this.printAnalyzerResult(); throw new Error(e); } this.sourcesFrames = sourceAnalyzer.getFrames(); ListIterator<AbstractInsnNode> iter = this.instructions.iterator(); HashMap<AbstractInsnNode, InsnList> instructionsToAddBefore = new HashMap<AbstractInsnNode, InsnList>(); HashMap<AbstractInsnNode, InsnList> instructionsToAddAfter = new HashMap<AbstractInsnNode, InsnList>(); HashMap<AbstractInsnNode, AbstractInsnNode> instructionsToReplace = new HashMap<AbstractInsnNode, AbstractInsnNode>(); while (iter.hasNext()) { AbstractInsnNode insnNode = iter.next(); int opcode; switch ((opcode = insnNode.getOpcode())) { case INVOKESPECIAL: { MethodInsnNode methodNode = (MethodInsnNode) insnNode; int receiverDepth = Type.getArgumentTypes(methodNode.desc).length; if (!this.needsRedirect(insnNode, receiverDepth)) continue; for (AbstractInsnNode source : this.getSources(insnNode, receiverDepth)) { if (source.getOpcode() == AALOAD) // Already instrumented, skip it continue; instructionsToAddAfter.put(source, this.ensureNotProxy(methodNode.owner)); } break; } case INVOKEVIRTUAL: { MethodInsnNode methodNode = (MethodInsnNode) insnNode; MethodInvocationInfo m = new MethodInvocationInfo(methodNode.name, methodNode.owner, methodNode.desc); if (ensureNotProxyMethods.contains(m)) { int receiverDepth = 0; for (Type arg : Type.getArgumentTypes(methodNode.desc)) receiverDepth += arg.getSize(); if (!this.needsRedirect(insnNode, receiverDepth)) continue; for (AbstractInsnNode source : this.getSources(insnNode, receiverDepth)) instructionsToAddAfter.put(source, this.ensureNotProxy()); } break; } case GETFIELD: { if (!this.needsRedirect(insnNode, 0)) continue; FieldInsnNode fieldNode = (FieldInsnNode) insnNode; Type fieldOwner = findActualFieldOwner(Type.getObjectType(fieldNode.owner), fieldNode.name); opcode = (opcode == GETFIELD ? INVOKEVIRTUAL : INVOKESTATIC); String methodName = AddGettersAndSetters.generateGetterName(version, fieldOwner, fieldNode.name); String methodDesc = Type.getMethodDescriptor(Type.getType(fieldNode.desc)); instructionsToReplace.put(insnNode, new MethodInsnNode(opcode, fieldNode.owner, methodName, methodDesc, false)); break; } case PUTFIELD: { if (!this.needsRedirect(insnNode, 1)) continue; FieldInsnNode fieldNode = (FieldInsnNode) insnNode; Type fieldOwner = findActualFieldOwner(Type.getObjectType(fieldNode.owner), fieldNode.name); opcode = (opcode == PUTFIELD ? INVOKEVIRTUAL : INVOKESTATIC); String methodName = AddGettersAndSetters.generateSetterName(version, fieldOwner, fieldNode.name); String methodDesc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(fieldNode.desc)); instructionsToReplace.put(insnNode, new MethodInsnNode(opcode, fieldNode.owner, methodName, methodDesc, false)); break; } } } for (Entry<AbstractInsnNode, InsnList> entry : instructionsToAddBefore.entrySet()) this.instructions.insertBefore(entry.getKey(), entry.getValue()); for (Entry<AbstractInsnNode, InsnList> entry : instructionsToAddAfter.entrySet()) this.instructions.insert(entry.getKey(), entry.getValue()); // Destructive changes take place after constructive changes // so that the location nodes do not get destroyed too soon for (Entry<AbstractInsnNode, AbstractInsnNode> entry : instructionsToReplace.entrySet()) this.instructions.set(entry.getKey(), entry.getValue()); accept(methodVisitor); } private InsnList ensureNotProxy() { return this.ensureNotProxy(null); } private InsnList ensureNotProxy(String owner) { InsnList list = new InsnList(); LabelNode label = new LabelNode(); list.add(new InsnNode(DUP)); list.add(new TypeInsnNode(INSTANCEOF, Type.getType(RubahProxy.class).getInternalName())); list.add(new JumpInsnNode(IFEQ, label)); list.add(new TypeInsnNode(CHECKCAST, Type.getType(RubahProxy.class).getInternalName())); list.add(new MethodInsnNode(INVOKESTATIC, Type.getType(Rubah.class).getInternalName(), "getConverted", Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class)), false)); if (owner != null) list.add(new TypeInsnNode(CHECKCAST, owner)); list.add(label); return list; } /** * * @param idx * @return True if local var, false if argument */ private boolean isLocalVar(int idx) { int lastVar = (this.isStatic ? 0 : 1); for (Type arg : Type.getArgumentTypes(desc)) lastVar += arg.getSize(); return idx >= lastVar; } private Set<AbstractInsnNode> getSources(AbstractInsnNode insnNode, int depth) { return this.getSources(insnNode, depth, new HashSet<AbstractInsnNode>(), new HashSet<AbstractInsnNode>()); } private Set<AbstractInsnNode> getSources(AbstractInsnNode insnNode, int depth, HashSet<AbstractInsnNode> allSources, HashSet<AbstractInsnNode> alreadySeen) { int idx = this.instructions.indexOf(insnNode); Frame<SourceValue> sourcesFrame = this.sourcesFrames[idx]; if (sourcesFrame == null) { // Bug in the analyzer or unreachable code return new HashSet<AbstractInsnNode>(); } Set<AbstractInsnNode> sources = sourcesFrame .getStack(sourcesFrame.getStackSize() - 1 - depth).insns; for (AbstractInsnNode source : sources) { if (alreadySeen.contains(source)) continue; alreadySeen.add(source); switch (source.getOpcode()) { case CHECKCAST: case DUP: allSources.addAll(this.getSources(source, 0, allSources, alreadySeen)); break; case ALOAD: // Is this an argument? VarInsnNode n = (VarInsnNode) source; if (isLocalVar(n.var)) { // Only ASTORE can save to local variables for (AbstractInsnNode astore : sourcesFrame.getLocal(n.var).insns) { allSources.addAll(this.getSources(astore, 0, allSources, alreadySeen)); } continue; } // Explicit fall-through default: allSources.add(source); break; } } return allSources; } private void printAnalyzerResult() { Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); PrintWriter pw = new PrintWriter(System.out); pw.println(this.name + this.desc); for (int j = 0; j < this.instructions.size(); ++j) { this.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame<SourceValue> f = this.sourcesFrames[j]; if (f == null) { s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { for (AbstractInsnNode insn : f.getLocal(k).insns) { s.append(this.instructions.indexOf(insn)).append(' '); } } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { for (AbstractInsnNode insn : f.getStack(k).insns) { s.append(this.instructions.indexOf(insn)).append(' '); } } } while (s.length() < this.maxStack + this.maxLocals + 1) { s.append(' '); } pw.print(Integer.toString(j + 100000).substring(1)); pw.print(" " + s + " : " + t.text.get(t.text.size() - 1)); } for (int j = 0; j < this.tryCatchBlocks.size(); ++j) { this.tryCatchBlocks.get(j).accept(mv); pw.print(" " + t.text.get(t.text.size() - 1)); } pw.println(); pw.flush(); } private boolean needsRedirect(AbstractInsnNode insnNode, int stackDepth) { boolean ret = false; for (AbstractInsnNode insn : this.getSources(insnNode, stackDepth)) { switch (insn.getOpcode()) { case NEW: continue; case ALOAD: if (((VarInsnNode) insn).var != 0 || this.isStatic) ret = true; break; default: ret = true; break; } } return ret; } }; return ret; }
From source file:uk.co.mysterymayhem.tessellatorfix.Transformer.java
private static byte[] patchTessellatorClass(byte[] bytes) { String targetMethodName;//from w ww .ja va 2 s. c om if (Plugin.runtimeDeobfEnabled) { targetMethodName = "func_147564_a"; } else { targetMethodName = "getVertexState"; } ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); Iterator<MethodNode> methods = classNode.methods.iterator(); while (methods.hasNext()) { MethodNode m = methods.next(); if ((m.name.equals(targetMethodName) && m.desc.equals("(FFF)Lnet/minecraft/client/shader/TesselatorVertexState;"))) { FMLLog.info("Inside target Tessellator method"); InsnList toInject = new InsnList(); // Insertion of "if (this.rawBufferIndex < 1) return" LabelNode labelNode = new LabelNode(); toInject.add(new VarInsnNode(Opcodes.ALOAD, 0)); String fieldName; if (Plugin.runtimeDeobfEnabled) { fieldName = "field_147569_p"; } else { fieldName = "rawBufferIndex"; } toInject.add(new FieldInsnNode(Opcodes.GETFIELD, "net/minecraft/client/renderer/Tessellator", fieldName, "I")); toInject.add(new InsnNode(Opcodes.ICONST_1)); toInject.add(new JumpInsnNode(Opcodes.IF_ICMPGE, labelNode)); toInject.add(new InsnNode(Opcodes.ACONST_NULL)); toInject.add(new InsnNode(Opcodes.ARETURN)); toInject.add(labelNode); // Insert after m.instructions.insert(toInject); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); FMLLog.info("Exiting target Tessellator method"); return writer.toByteArray(); } } FMLLog.warning("Could not find Tessellator method out of:"); StringBuilder builder = new StringBuilder(); for (MethodNode methodNode : classNode.methods) { builder.append(methodNode.name).append(":").append(methodNode.desc).append("\n"); } FMLLog.info(builder.toString()); return bytes; }
From source file:vazkii.quark.base.asm.ClassTransformer.java
License:Creative Commons License
private static byte[] transformModelBiped(byte[] basicClass) { log("Transforming ModelBiped"); MethodSignature sig = new MethodSignature("setRotationAngles", "func_78087_a", "a", "(FFFFFFLnet/minecraft/entity/Entity;)V"); return transform(basicClass, Pair.of(sig, combine((AbstractInsnNode node) -> { // Filter return node.getOpcode() == Opcodes.RETURN; }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new VarInsnNode(Opcodes.ALOAD, 7)); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "updateEmotes", "(Lnet/minecraft/entity/Entity;)V")); method.instructions.insertBefore(node, newInstructions); return true; })));//www . j ava 2 s . c o m }
From source file:vazkii.quark.base.asm.ClassTransformer.java
License:Creative Commons License
private static byte[] transformRenderItem(byte[] basicClass) { log("Transforming RenderItem"); MethodSignature sig1 = new MethodSignature("renderItem", "func_180454_a", "a", "(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/renderer/block/model/IBakedModel;)V"); MethodSignature sig2 = new MethodSignature("renderEffect", "func_191966_a", "a", "(Lnet/minecraft/client/renderer/block/model/IBakedModel;)V"); byte[] transClass = basicClass; transClass = transform(transClass, Pair.of(sig1, combine((AbstractInsnNode node) -> { // Filter return true; }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "setColorRuneTargetStack", "(Lnet/minecraft/item/ItemStack;)V")); method.instructions.insertBefore(node, newInstructions); return true; })));//from w ww.j a va 2s . c om transClass = transform(transClass, Pair.of(sig2, combine((AbstractInsnNode node) -> { // Filter return node.getOpcode() == Opcodes.LDC && ((LdcInsnNode) node).cst.equals(-8372020); }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "getRuneColor", "(I)I")); method.instructions.insert(node, newInstructions); return false; }))); return transClass; }
From source file:vazkii.quark.base.asm.ClassTransformer.java
License:Creative Commons License
private static byte[] transformLayerArmorBase(byte[] basicClass) { log("Transforming LayerArmorBase"); MethodSignature sig1 = new MethodSignature("renderArmorLayer", "func_188361_a", "a", "(Lnet/minecraft/entity/EntityLivingBase;FFFFFFFLnet/minecraft/inventory/EntityEquipmentSlot;)V"); MethodSignature sig2 = new MethodSignature("renderEnchantedGlint", "func_188364_a", "a", "(Lnet/minecraft/client/renderer/entity/RenderLivingBase;Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/client/model/ModelBase;FFFFFFF)V"); byte[] transClass = basicClass; transClass = transform(transClass, Pair.of(sig1, combine((AbstractInsnNode node) -> { // Filter return node.getOpcode() == Opcodes.ASTORE; }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new VarInsnNode(Opcodes.ALOAD, 10)); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "setColorRuneTargetStack", "(Lnet/minecraft/item/ItemStack;)V")); method.instructions.insert(node, newInstructions); return true; })));// w ww .j a va 2s . c o m if (!hasOptifine(sig2.toString())) { invokestaticCount = 0; transClass = transform(transClass, Pair.of(sig2, combine((AbstractInsnNode node) -> { // Filter return node.getOpcode() == Opcodes.INVOKESTATIC && ((MethodInsnNode) node).desc.equals("(FFFF)V"); }, (MethodNode method, AbstractInsnNode node) -> { // Action invokestaticCount++; InsnList newInstructions = new InsnList(); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "applyRuneColor", "()V")); method.instructions.insert(node, newInstructions); return invokestaticCount == 2; }))); } return transClass; }
From source file:vazkii.quark.base.asm.ClassTransformer.java
License:Creative Commons License
private static byte[] transformEntityBoat(byte[] basicClass) { log("Transforming EntityBoat"); MethodSignature sig1 = new MethodSignature("attackEntityFrom", "func_70097_a", "a", "(Lnet/minecraft/util/DamageSource;F)Z"); MethodSignature sig2 = new MethodSignature("onUpdate", "func_70071_h_", "B_", "()V"); byte[] transClass = transform(basicClass, Pair.of(sig1, combine((AbstractInsnNode node) -> { // Filter return node.getOpcode() == Opcodes.POP; }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "dropBoatBanner", "(Lnet/minecraft/entity/item/EntityBoat;)V")); method.instructions.insertBefore(node, newInstructions); return true; })));// www .j av a2s . c om transClass = transform(transClass, Pair.of(sig2, combine((AbstractInsnNode node) -> { // Filter return true; }, (MethodNode method, AbstractInsnNode node) -> { // Action InsnList newInstructions = new InsnList(); newInstructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); newInstructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, ASM_HOOKS, "onBoatUpdate", "(Lnet/minecraft/entity/item/EntityBoat;)V")); method.instructions.insertBefore(node, newInstructions); return true; }))); return transClass; }