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;
+ }
+
}