Fixed FELIX-3574

Applying the patch from Francois Valdy. Added some comments.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1354636 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/manipulator/pom.xml b/ipojo/manipulator/manipulator/pom.xml
index a178fbe..d4b0c99 100644
--- a/ipojo/manipulator/manipulator/pom.xml
+++ b/ipojo/manipulator/manipulator/pom.xml
@@ -38,12 +38,6 @@
             <groupId>asm</groupId>
             <artifactId>asm-all</artifactId>
             <version>3.3.1</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>asm</groupId>
-                    <artifactId>asm-tree</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>
@@ -86,7 +80,7 @@
                         <Private-Package>org.apache.felix.ipojo.manipulation,
                             org.apache.felix.ipojo.manipulation.annotations,
                             org.apache.felix.ipojo.xml.parser, org.objectweb.asm,
-                            org.objectweb.asm.commons
+                            org.objectweb.asm.commons, org.objectweb.asm.tree
                         </Private-Package>
                         <Include-Resource>
                             META-INF/LICENSE=LICENSE,
@@ -95,7 +89,7 @@
                             META-INF/DEPENDENCIES=DEPENDENCIES,
                             {maven-resources}
                         </Include-Resource>
-                        <Import-Package>!org.objectweb.asm.tree, *</Import-Package>
+                        <Import-Package>*</Import-Package>
                     </instructions>
                     <obrRepository>NONE</obrRepository>
                 </configuration>
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
index 2072c23..cd804a6 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -22,10 +22,10 @@
 import java.util.List;

 import java.util.Map;

 import java.util.TreeMap;

-

 import org.objectweb.asm.AnnotationVisitor;

 import org.objectweb.asm.ClassVisitor;

 import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.Label;

 import org.objectweb.asm.MethodVisitor;

 import org.objectweb.asm.Opcodes;

 import org.objectweb.asm.Type;

@@ -215,20 +215,16 @@
 

             if (name.equals("<init>")) {

                 if (!isGeneratedConstructor(name, desc)) {

-                    final MethodDescriptor md = new MethodDescriptor("$init", desc);

+                    final MethodDescriptor md = new MethodDescriptor("$init", desc, (access & ACC_STATIC) == ACC_STATIC);

                     m_methods.add(md);

-                    if (m_supportAnnotation) {

-                        return new AnnotationCollector(md);

-                    }

+                    return new MethodInfoCollector(md);

                 }

             } else {

                 // no constructors.

                 if (!isGeneratedMethod(name, desc)) {

-                    final MethodDescriptor md = new MethodDescriptor(name, desc);

+                    final MethodDescriptor md = new MethodDescriptor(name, desc, (access & ACC_STATIC) == ACC_STATIC);

                     m_methods.add(md);

-                    if (m_supportAnnotation) {

-                        return new AnnotationCollector(md);

-                    }

+                    return new MethodInfoCollector(md);

                 }

             }

 

@@ -323,9 +319,10 @@
      * This class collects annotations in a method.

      * This class creates an {@link AnnotationDescriptor}

      * if an annotation is found during the visit.

+     * It also collects local variables definition.

      *  @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

      */

-    private final class AnnotationCollector extends EmptyVisitor {

+    private final class MethodInfoCollector extends EmptyVisitor {

         /**

          * The method descriptor of the visited method.

          */

@@ -335,7 +332,7 @@
          * Creates an annotation collector.

          * @param md the method descriptor of the visited method.

          */

-        private AnnotationCollector(MethodDescriptor md) {

+        private MethodInfoCollector(MethodDescriptor md) {

             m_method = md;

         }

 

@@ -359,6 +356,14 @@
             }

             return null;

         }

+        

+        public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {

+            m_method.addLocalVariable(name, desc, signature, index);

+        }

+        

+        public void visitEnd() {

+            m_method.end();

+        }

 

         public AnnotationVisitor visitParameterAnnotation(int id,

                 String name, boolean visible) {

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
index 3b65dff..d3401c4 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
@@ -33,6 +33,7 @@
 import org.objectweb.asm.Opcodes;

 import org.objectweb.asm.Type;

 import org.objectweb.asm.commons.GeneratorAdapter;

+import org.objectweb.asm.tree.LocalVariableNode;

 

 /**

  * iPOJO Class Adapter.

@@ -218,9 +219,9 @@
 

         MethodDescriptor md = getMethodDescriptor(name, desc);

         if (md == null) {

-            generateMethodHeader(access, name, desc, signature, exceptions, null, null);

+            generateMethodHeader(access, name, desc, signature, exceptions, null, null, null);

         } else {

-            generateMethodHeader(access, name, desc, signature, exceptions, md.getAnnotations(), md.getParameterAnnotations());

+            generateMethodHeader(access, name, desc, signature, exceptions, md.getArgumentLocalVariables(), md.getAnnotations(), md.getParameterAnnotations());

         }

 

         String id = generateMethodFlag(name, desc);

@@ -356,12 +357,22 @@
      * @param desc : method descriptor.

      * @param signature : method signature.

      * @param exceptions : declared exceptions.

+     * @param localVariables : the local variable nodes.

      * @param annotations : the annotations to move to this method.

      * @param paramAnnotations : the parameter annotations to move to this method.

      */

-    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions, List<AnnotationDescriptor> annotations, Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {

+    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions, List<LocalVariableNode> localVariables, List<AnnotationDescriptor> annotations, Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {

         GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc);

 

+        // If we have variables, we wraps the code within labels. The `lifetime` of the variables are bound to those

+        // two variables.

+        boolean hasArgumentLabels = localVariables != null && !localVariables.isEmpty();

+        Label start = null;

+        if (hasArgumentLabels) {

+            start = new Label();

+            mv.visitLabel(start);

+        }

+

         mv.visitCode();

 

         Type returnType = Type.getReturnType(desc);

@@ -449,6 +460,13 @@
         }

         mv.visitInsn(returnType.getOpcode(IRETURN));

 

+        // If we had arguments, we mark the end of the lifetime.

+        Label end = null;

+        if (hasArgumentLabels) {

+            end = new Label();

+            mv.visitLabel(end);

+        }

+

         // Move annotations

         if (annotations != null) {

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

@@ -470,6 +488,13 @@
             }

         }

 

+        // Write the arguments name.

+        if (hasArgumentLabels) {

+            for (LocalVariableNode var : localVariables) {

+                mv.visitLocalVariable(var.name, var.desc, var.signature, start, end, var.index);

+            }

+        }

+

         mv.visitMaxs(0, 0);

         mv.visitEnd();

     }

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
index c715010..025dca3 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -19,14 +19,16 @@
 package org.apache.felix.ipojo.manipulation;

 

 import java.util.ArrayList;

+import java.util.Collections;

+import java.util.Comparator;

 import java.util.HashMap;

 import java.util.List;

 import java.util.Map;

-

 import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;

 import org.apache.felix.ipojo.metadata.Attribute;

 import org.apache.felix.ipojo.metadata.Element;

 import org.objectweb.asm.Type;

+import org.objectweb.asm.tree.LocalVariableNode;

 

 /**

  * Method Descriptor describe a method.

@@ -67,21 +69,47 @@
     private Map<Integer, List<AnnotationDescriptor>> m_parameterAnnotations = new HashMap<Integer, List<AnnotationDescriptor>>();

 

     /**

+     * The arguments variables.

+     */

+    private List<LocalVariableNode> m_argLocalVariables;

+

+    /**

+     * The stack size to keep of the arguments.

+     */

+    private final int m_argsVarLength;

+

+    /**

+     * Flag indicating is the described method is static.

+     */

+    private final boolean m_isStatic;

+

+    /**

      * Constructor.

      * @param name : name of the method.

      * @param desc : descriptor of the method.

+     * @param isStatic : is the method static

      */

-    public MethodDescriptor(String name, String desc) {

+    public MethodDescriptor(String name, String desc, boolean isStatic) {

         m_name = name;

         m_desc = desc;

+        m_isStatic = isStatic;

         Type ret = Type.getReturnType(desc);

         Type[] args = Type.getArgumentTypes(desc);

 

         m_returnType = getType(ret);

         m_arguments = new String[args.length];

-        for (int i = 0; i < args.length; i++) {

-            m_arguments[i] = getType(args[i]);

+        int argsVarLength = args.length;

+        if (!m_isStatic) {

+            argsVarLength++;

         }

+        for (int i = 0; i < args.length; i++) {

+            String type = getType(args[i]);

+            m_arguments[i] = type;

+            if ("long".equals(type) || "double".equals(type)) {

+                argsVarLength++;

+            }

+        }

+        m_argsVarLength = argsVarLength;

     }

 

     /**

@@ -186,4 +214,30 @@
         return m_name;

     }

 

+    public void addLocalVariable(String name, String desc, String signature, int index) {

+        if (index >= m_argsVarLength) {

+            // keep only argument-related local variables definitions (others relate to code which isn't in this method) 

+            return;

+        }

+        if (m_argLocalVariables == null) {

+            m_argLocalVariables = new ArrayList<LocalVariableNode>();

+        }

+        m_argLocalVariables.add(new LocalVariableNode(name, desc, signature, null, null, index));

+    }

+

+    public void end() {

+        if (m_argLocalVariables != null && m_argLocalVariables.size() > 1) {

+            // sort them by index, even if from experience, argument-related variables (and only those) are already sorted

+            Collections.sort(m_argLocalVariables, new Comparator<LocalVariableNode>(){

+                public int compare(LocalVariableNode o1, LocalVariableNode o2) {

+                    return o1.index - o2.index;

+                }

+            });

+        }

+    }

+

+    public List<LocalVariableNode> getArgumentLocalVariables() {

+        return m_argLocalVariables;

+    }

+

 }