Author: kohsuke Date: Tue Jan 3 23:41:11 2006 New Revision: 365853 URL: http://svn.apache.org/viewcvs?rev=365853&view=rev Log: applied another patch (but this time manually!) from Eugene.
Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/transformation/asm/ContinuationMethodAnalyzer.java Modified: jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/transformation/asm/ContinuationMethodAnalyzer.java URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/transformation/asm/ContinuationMethodAnalyzer.java?rev=365853&r1=365852&r2=365853&view=diff ============================================================================== --- jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/transformation/asm/ContinuationMethodAnalyzer.java (original) +++ jakarta/commons/sandbox/javaflow/trunk/src/java/org/apache/commons/javaflow/bytecode/transformation/asm/ContinuationMethodAnalyzer.java Tue Jan 3 23:41:11 2006 @@ -38,12 +38,12 @@ import org.objectweb.asm.tree.analysis.DataflowInterpreter; import org.objectweb.asm.tree.analysis.DataflowValue; import org.objectweb.asm.tree.analysis.Frame; -import org.objectweb.asm.tree.analysis.BasicVerifier; +import org.objectweb.asm.tree.analysis.SimpleVerifier; /** * ContinuationMethodAdapter - * + * * @author Evgueni Koulechov */ public class ContinuationMethodAnalyzer extends MethodNode implements Opcodes { @@ -84,14 +84,34 @@ public void visitEnd() { if(instructions.size()==0 || labels.size()==0) { accept(mv); - return; - } - - this.stackRecorderVar = maxLocals; - try { - moveNew(); + return; + } - analyzer = new Analyzer(new BasicVerifier()); + this.stackRecorderVar = maxLocals; + try { + moveNew(); + +// TraceMethodVisitor mv = new TraceMethodVisitor(); +// System.err.println(name + desc); +// for (int j = 0; j < instructions.size(); ++j) { +// ((AbstractInsnNode) instructions.get(j)).accept(mv); +// System.err.print(" " + mv.text.get(j)); // mv.text.get(j)); +// } +// System.err.println(); + + // analyzer = new Analyzer(new BasicVerifier()); + analyzer = new Analyzer(new SimpleVerifier() { + protected Class getClass( Type t) { + try { + if (t.getSort() == Type.ARRAY) { + return Class.forName(t.getDescriptor().replace('/', '.'), true, Thread.currentThread().getContextClassLoader()); + } + return Class.forName(t.getClassName(), true, Thread.currentThread().getContextClassLoader()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e.toString()); + } + } + }); analyzer.analyze(className, this); accept(new ContinuationMethodAdapter(this)); @@ -124,63 +144,121 @@ AbstractInsnNode ins = (AbstractInsnNode) it.next(); if(ins.getOpcode()==NEW) { movable.put(ins, mnode); - } else if(ins.getOpcode()==DUP) { + } else { + // other known patterns int n1 = a.getIndex(ins); - AbstractInsnNode ins1 = (AbstractInsnNode) instructions.get(n1-1); - if(ins1.getOpcode()==NEW) { - movable.put(ins1, mnode); + if(ins.getOpcode()==DUP) { // <init> with params + AbstractInsnNode ins1 = (AbstractInsnNode) instructions.get(n1-1); + if(ins1.getOpcode()==NEW) { + movable.put(ins1, mnode); + } + } else if(ins.getOpcode()==SWAP) { // in exception handler + AbstractInsnNode ins1 = (AbstractInsnNode) instructions.get(n1-1); + AbstractInsnNode ins2 = (AbstractInsnNode) instructions.get(n1-2); + if(ins1.getOpcode()==DUP_X1 && ins2.getOpcode()==NEW) { + movable.put(ins2, mnode); + } } - } - } + } + } } - for( Iterator it = movable.entrySet().iterator(); it.hasNext();) { - Map.Entry e = (Map.Entry) it.next(); - AbstractInsnNode node1 = (AbstractInsnNode) e.getKey(); - int n1 = instructions.indexOf(node1); - AbstractInsnNode node2 = (AbstractInsnNode) instructions.get(n1+1); - boolean hasCopy = node2.getOpcode()==DUP; - - instructions.remove(node1); // NEW - if(hasCopy) { - instructions.remove(node2); // DUP - } + int updateMaxStack = 0; + for( Iterator it = movable.entrySet().iterator(); it.hasNext();) { + Map.Entry e = (Map.Entry) it.next(); + AbstractInsnNode node1 = (AbstractInsnNode) e.getKey(); + int n1 = instructions.indexOf(node1); + AbstractInsnNode node2 = (AbstractInsnNode) instructions.get(n1+1); + AbstractInsnNode node3 = (AbstractInsnNode) instructions.get(n1+2); + int producer = node2.getOpcode(); + + instructions.remove(node1); // NEW + boolean requireDup = false; + if(producer==DUP) { + instructions.remove(node2); // DUP + requireDup = true; + } else if(producer==DUP_X1) { + instructions.remove(node2); // DUP_X1 + instructions.remove(node3); // SWAP + requireDup = true; + } - MethodInsnNode mnode = (MethodInsnNode) e.getValue(); - int nm = instructions.indexOf(mnode); + MethodInsnNode mnode = (MethodInsnNode) e.getValue(); + int nm = instructions.indexOf(mnode); - int varOffset = stackRecorderVar+1; - Type[] args = Type.getArgumentTypes(mnode.desc); + int varOffset = stackRecorderVar+1; + Type[] args = Type.getArgumentTypes(mnode.desc); - // save stack - for (int j = args.length - 1; j >= 0; j--) { - Type type = args[j]; - instructions.add(nm++, new VarInsnNode(type.getOpcode(ISTORE), varOffset)); - varOffset += type.getSize(); - } - if(varOffset>maxLocals) { - maxLocals = varOffset; - } + // optimizations for some common cases + if(args.length==0) { + instructions.add(nm++, node1); // NEW + if(requireDup) { + instructions.add(nm++, new InsnNode(DUP)); + } + continue; + } - instructions.add(nm++, node1); // NEW - if(hasCopy) { - instructions.add(nm++, node2); // DUP - } + if(args.length==1 && args[0].getSize()==1) { + instructions.add(nm++, node1); // NEW + if(requireDup) { + instructions.add(nm++, new InsnNode(DUP)); + instructions.add(nm++, new InsnNode(DUP2_X1)); + instructions.add(nm++, new InsnNode(POP2)); + updateMaxStack = updateMaxStack<2 ? 2 : updateMaxStack; // a two extra slots for temp values + } else { + instructions.add(nm++, new InsnNode(SWAP)); + } + continue; + } + + // TODO this one untested! + if((args.length==1 && args[0].getSize()==2) || + (args.length==2 && args[0].getSize()==1 && args[1].getSize()==1)) { + instructions.add(nm++, node1); // NEW + if(requireDup) { + instructions.add(nm++, new InsnNode(DUP)); + instructions.add(nm++, new InsnNode(DUP2_X2)); + instructions.add(nm++, new InsnNode(POP2)); + updateMaxStack = updateMaxStack<2 ? 2 : updateMaxStack; // a two extra slots for temp values + } else { + instructions.add(nm++, new InsnNode(DUP_X2)); + instructions.add(nm++, new InsnNode(POP)); + updateMaxStack = updateMaxStack<1 ? 1 : updateMaxStack; // an extra slot for temp value + } + continue; + } - // restore stack + // generic code using temporary locals + // save stack + for (int j = args.length - 1; j >= 0; j--) { + Type type = args[j]; + instructions.add(nm++, new VarInsnNode(type.getOpcode(ISTORE), varOffset)); + varOffset += type.getSize(); + } + if(varOffset>maxLocals) { + maxLocals = varOffset; + } + + instructions.add(nm++, node1); // NEW + if(requireDup) { + instructions.add(nm++, new InsnNode(DUP)); + } + + // restore stack for( int j = 0; j < args.length; j++) { Type type = args[j]; varOffset -= type.getSize(); instructions.add(nm++, new VarInsnNode(type.getOpcode(ILOAD), varOffset)); // clean up store to avoid memory leak? if(type.getSort()==Type.OBJECT || type.getSort()==Type.ARRAY) { + updateMaxStack = updateMaxStack<1 ? 1 : updateMaxStack; // an extra slot for ACONST_NULL instructions.add(nm++, new InsnNode(ACONST_NULL)); instructions.add(nm++, new VarInsnNode(type.getOpcode(ISTORE), varOffset)); } } } - // TODO: when we move the NEW instructions, we need to update the maxStacks - // accordingly + + maxStack += updateMaxStack; } // TODO --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]