diff --git a/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java b/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java index e003be9bd..bd0da422c 100644 --- a/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java +++ b/dex-translator/src/main/java/com/googlecode/d2j/dex/ExDex2Asm.java @@ -16,6 +16,7 @@ */ package com.googlecode.d2j.dex; +import org.objectweb.asm.AsmBridge; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.MethodNode; @@ -32,7 +33,7 @@ public ExDex2Asm(DexExceptionHandler exceptionHandler) { @Override public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) { -// MethodVisitor mw = AsmBridge.searchMethodWriter(mv); + MethodVisitor mw = AsmBridge.searchMethodWriter(mv); MethodNode mn = new MethodNode(Opcodes.ASM9, methodNode.access, methodNode.method.getName(), methodNode.method.getDesc(), null, null); try { @@ -48,15 +49,15 @@ public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCt } // code convert ok, copy to MethodWriter and check for Size mn.accept(mv); -// if (mw != null) { -// try { -// AsmBridge.sizeOfMethodWriter(mw); -// } catch (Exception ex) { -// mn.instructions.clear(); -// mn.tryCatchBlocks.clear(); -// exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); -// AsmBridge.replaceMethodWriter(mw, mn); -// } -// } + if (mw != null) { + try { + AsmBridge.sizeOfMethodWriter(mw); + } catch (Exception ex) { + mn.instructions.clear(); + mn.tryCatchBlocks.clear(); + exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); + AsmBridge.replaceMethodWriter(mw, mn); + } + } } } diff --git a/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java b/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java new file mode 100644 index 000000000..b2fd06ca7 --- /dev/null +++ b/dex-translator/src/main/java/org/objectweb/asm/AsmBridge.java @@ -0,0 +1,101 @@ +/* + * dex2jar - Tools to work with android .dex and java .class files + * Copyright (c) 2009-2014 Panxiaobo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.objectweb.asm; + +import java.lang.reflect.Field; +import org.objectweb.asm.tree.MethodNode; + +public final class AsmBridge { + + public static MethodVisitor searchMethodWriter(MethodVisitor methodVisitor) { + while (methodVisitor != null && !(methodVisitor instanceof MethodWriter)) { + methodVisitor = methodVisitor.mv; + } + return methodVisitor; + } + + public static int sizeOfMethodWriter(MethodVisitor methodVisitor) { + MethodWriter mw = (MethodWriter) methodVisitor; + return mw.computeMethodInfoSize(); + } + + private static void removeMethodWriter(MethodWriter methodWriter) { + MethodWriter firstMethodWriter; + MethodWriter lastMethodWriter; + + try { + ClassWriter classWriter = reflectForClassWriter(methodWriter); + + Field fmField = ClassWriter.class.getDeclaredField("firstMethod"); + fmField.setAccessible(true); + firstMethodWriter = (MethodWriter) fmField.get(classWriter); + + Field lmField = ClassWriter.class.getDeclaredField("lastMethod"); + lmField.setAccessible(true); + lastMethodWriter = (MethodWriter) lmField.get(classWriter); + + // mv must be the last element + if (firstMethodWriter == methodWriter) { + fmField.set(classWriter, null); + if (lastMethodWriter == methodWriter) { + lmField.set(classWriter, null); + } + } else { + while (firstMethodWriter != null) { + if (firstMethodWriter.mv == methodWriter) { + firstMethodWriter.mv = methodWriter.mv; + if (lastMethodWriter == methodWriter) { + lmField.set(classWriter, firstMethodWriter); + } + break; + } else { + firstMethodWriter = (MethodWriter) firstMethodWriter.mv; + } + } + } + } catch (IllegalAccessException | NoSuchFieldException exc) { + exc.printStackTrace(); + } + } + + private static ClassWriter reflectForClassWriter(MethodWriter methodWriter) throws NoSuchFieldException, IllegalAccessException { + // Get the SymbolTable for accessing ClassWriter + Field stField = MethodWriter.class.getDeclaredField("symbolTable"); + stField.setAccessible(true); + SymbolTable symbolTable = (SymbolTable) stField.get(methodWriter); + // Get ClassWriter object from methodWriter's SymbolTable + return symbolTable.classWriter; + } + + public static void replaceMethodWriter(MethodVisitor methodVisitor, MethodNode methodNode) { + MethodWriter methodWriter = (MethodWriter) methodVisitor; + + try { + ClassWriter classWriter = reflectForClassWriter(methodWriter); + + methodNode.accept(classWriter); + removeMethodWriter(methodWriter); + } catch (IllegalAccessException | NoSuchFieldException exc) { + exc.printStackTrace(); + } + } + + private AsmBridge() { + throw new UnsupportedOperationException(); + } + +}