[jboss-svn-commits] JBL Code SVN: r28931 - in labs/jbosstm/workspace/adinn/byteman/trunk: src/org/jboss/byteman/rule/binding and 5 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Aug 14 06:17:43 EDT 2009


Author: adinn
Date: 2009-08-14 06:17:43 -0400 (Fri, 14 Aug 2009)
New Revision: 28931

Added:
   labs/jbosstm/workspace/adinn/byteman/trunk/tests/dd/scripts/bugfixes/TestMethodParamName.txt
   labs/jbosstm/workspace/adinn/byteman/trunk/tests/src/org/jboss/byteman/tests/bugfixes/TestMethodParamName.java
Modified:
   labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/adapter/RuleTriggerMethodAdapter.java
   labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/binding/Binding.java
   labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/compiler/Compiler.java
   labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/helper/InterpretedHelper.java
   labs/jbosstm/workspace/adinn/byteman/trunk/tests/build.xml
Log:
added support for referring to method arguments using symbol names e.g. ,  etc - fixes BYTEMAN-23

Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/adapter/RuleTriggerMethodAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/adapter/RuleTriggerMethodAdapter.java	2009-08-14 07:08:11 UTC (rev 28930)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/agent/adapter/RuleTriggerMethodAdapter.java	2009-08-14 10:17:43 UTC (rev 28931)
@@ -48,9 +48,10 @@
         super(mv, rule, access, name, descriptor);
         this.access = access;
         this.descriptor = descriptor;
-        this.paramBindings = new ArrayList<Binding>();
+        this.callArrayBindings = new ArrayList<Binding>();
         this.returnType = Type.getReturnType(descriptor);
         this.argumentTypes = Type.getArgumentTypes(descriptor);
+        this.argLocalIndices = new int[argumentTypes.length];
         this.bindingsDone = false;
         this.localTypes = new ArrayList();
     }
@@ -59,23 +60,63 @@
     {
         Bindings bindings = rule.getBindings();
         Iterator<Binding> iterator = bindings.iterator();
+        List<Binding> aliasBindings = new ArrayList<Binding>();
+        int argLocalIndex = 0;
 
-        // make sure all entries are valid
+        // if this is an instance method then the local 0 holds this and args start at local index 1
+
+        if ((access & Opcodes.ACC_STATIC) == 0) {
+            argLocalIndex += 1;
+        }
+
+        // compute the local indices of each method parameter
+
+        for (int i = 0; i < argumentTypes.length; i++) {
+            argLocalIndices[i] = argLocalIndex;
+            argLocalIndex += argumentTypes[i].getSize();
+        }
+
+        // check the local var bindings and, if any of them are actually refereces to method params
+        // alias them to the corresponding param binding
+
         while (iterator.hasNext()) {
             Binding binding = iterator.next();
+            if  (binding.isLocalVar()){
+                int localIdx = binding.getLocalIndex();
+                if (localIdx < argLocalIndex) {
+                    binding = alias(binding, bindings, localIdx);
+                    if (binding != null) {
+                        // the aliased param binding was not present so ensure it gets added to the
+                        // binding set once we have finished iterating. there is no need to add it
+                        // to the call bindings since we pass the aliased method param instead
+                        aliasBindings.add(binding);
+                    }
+                } else {
+                    callArrayBindings.add(binding);
+                }
+            }
+        }
+
+        bindings.addBindings(aliasBindings);
+        
+        // now iterate over the param vars and ensure they go into the call bindings list
+
+        iterator = bindings.iterator();
+        
+        while (iterator.hasNext()) {
+            Binding binding = iterator.next();
             if (binding.isParam()) {
-                paramBindings.add(binding);
+                callArrayBindings.add(binding);
             } else if (binding.isReturn()) {
                 // at some point we will allow reference to the current return value so we need
-                // to be sure that the method has a non-void return type bit for now we do nothing
-            } else if (binding.isLocalVar()){
-                paramBindings.add(binding);
+                // to be sure that the method has a non-void return type and that the location
+                // specifier is AT RETURN but for now we do nothing
             }
         }
         // we don't have to do this but it makes debgging easier
         
         if (true) {
-            // ok now sort the paramBindings for later use
+            // ok now sort the callArrayBindings for later use
 
             Comparator<Binding> comparator = new Comparator<Binding>() {
                 public int compare(Binding b1, Binding b2)
@@ -100,16 +141,57 @@
                 }
             };
 
-            Collections.sort(paramBindings, comparator);
+            Collections.sort(callArrayBindings, comparator);
         }
 
         // now give each binding a unique index in the object array
-        int n = paramBindings.size();
+        int n = callArrayBindings.size();
         for (int i = 0; i < n; i++) {
-            paramBindings.get(i).setObjectArrayIndex(i);
+            callArrayBindings.get(i).setCallArrayIndex(i);
         }
     }
 
+    private Binding alias(Binding binding, Bindings bindings, int localIdx)
+    {
+        if (((access & Opcodes.ACC_STATIC) == 0) && (localIdx == 0)) {
+            String name = "$0";
+            Binding alias = bindings.lookup(name);
+            if (alias == null) {
+                alias = new Binding(rule, name);
+                alias.setDescriptor(binding.getDescriptor());
+                alias.setLocalIndex(binding.getLocalIndex());
+                binding.aliasTo(alias);
+                // alias var was new so return it for addition to the binding set
+                return alias;
+            } else {
+                // just alias the binding
+                binding.aliasTo(alias);
+                return null;
+            }
+        }
+
+        for (int i = 0; i < argLocalIndices.length; i++) {
+            if (argLocalIndices[i] == localIdx) {
+                String name = "$" + (i + 1);
+                Binding alias = bindings.lookup(name);
+                if (alias == null) {
+                    alias = new Binding(rule, name);
+                    alias.setDescriptor(binding.getDescriptor());
+                    alias.setLocalIndex(binding.getLocalIndex());
+                    binding.aliasTo(alias);
+                    // alias var was new so return it for addition to the binding set
+                    return alias;
+                } else {
+                    // just alias the binding
+                    binding.aliasTo(alias);
+                    return null;
+                }
+            }
+        }
+
+        return null;
+    }
+
     public void doArgLoad()
     {
         if (!bindingsDone) {
@@ -117,19 +199,19 @@
             bindingsDone = true;
         }
         
-        if (paramBindings.size() ==  0) {
+        if (callArrayBindings.size() ==  0) {
             push((org.objectweb.asm.Type)null);
             return;
         }
 
-        int arraySize = paramBindings.size();
+        int arraySize = callArrayBindings.size();
 
         push(arraySize);
         Type objectType = Type.getType(Object.class);
         newArray(objectType);
 
         for (int i = 0; i < arraySize; i++) {
-            Binding binding = paramBindings.get(i);
+            Binding binding = callArrayBindings.get(i);
             dup();
             push(i);
             if (binding.isParam()) {
@@ -159,7 +241,8 @@
     private String descriptor;
     private Type returnType;
     private Type[] argumentTypes;
-    private List<Binding> paramBindings;
+    private int[] argLocalIndices;
+    private List<Binding> callArrayBindings;
     private boolean bindingsDone;
     private final List localTypes;
 

Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/binding/Binding.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/binding/Binding.java	2009-08-14 07:08:11 UTC (rev 28930)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/binding/Binding.java	2009-08-14 10:17:43 UTC (rev 28931)
@@ -60,6 +60,7 @@
         this.name = name;
         this.type = (type != null ? type : Type.UNDEFINED);
         this.value = value;
+        this.alias = null;
         // ok, check the name to see what type of binding we have
         if (name.matches("\\$[0-9].*")) {
             // $NNN references the method target or a parameter from 0 upwards
@@ -78,12 +79,16 @@
             // anything else must be a variable introduced in the BINDS clause
             index = BINDVAR;
         }
-        this.objectArrayIndex = 0;
+        this.callArrayIndex = 0;
     }
 
     public Type typeCheck(Type expected)
             throws TypeException
     {
+        if (alias != null) {
+            return alias.typeCheck(expected);
+        }
+        
         // value can be null if this is a rule method parameter
         if (value != null) {
             // type check the binding expression, using the bound variable's expected if it is known
@@ -112,7 +117,9 @@
 
     public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
     {
-        if (isBindVar()) {
+        if (alias != null) {
+            alias.compile(mv, currentStackHeights, maxStackHeights);
+        } else if (isBindVar()) {
             int currentStack = currentStackHeights.stackCount;
 
             // push the current helper instance i.e. this -- adds 1 to stack height
@@ -150,6 +157,9 @@
 
     public Expression getValue()
     {
+        if (alias != null) {
+            return alias.getValue();
+        }
         return value;
     }
 
@@ -163,6 +173,9 @@
 
     public Type getType()
     {
+        if (alias != null) {
+            return alias.getType();
+        }
         return type;
     }
 
@@ -171,18 +184,24 @@
         this.type = type;
     }
 
-    public int getObjectArrayIndex()
+    public int getCallArrayIndex()
     {
-        return objectArrayIndex;
+        if (alias != null) {
+            return alias.getCallArrayIndex();
+        }
+        return callArrayIndex;
     }
 
-    public void setObjectArrayIndex(int objectArrayIndex)
+    public void setCallArrayIndex(int callArrayIndex)
     {
-        this.objectArrayIndex = objectArrayIndex;
+        this.callArrayIndex = callArrayIndex;
     }
 
     public int getLocalIndex()
     {
+        if (alias != null) {
+            return alias.getLocalIndex();
+        }
         return localIndex;
     }
 
@@ -257,6 +276,26 @@
         }
     }
 
+
+    public void aliasTo(Binding alias)
+    {
+        if (this.isLocalVar()) {
+            this.alias = alias;
+        } else {
+            System.out.println("Binding : attempt to alias non-local var " + getName() + " to " + alias.getName());
+        }
+    }
+
+    public boolean isAlias()
+    {
+        return (alias != null);
+    }
+
+    public Binding getAlias()
+    {
+        return alias;
+    }
+
     // special index values for non-positional parameters
 
     private final static int HELPER = -1;
@@ -272,7 +311,8 @@
     // values for other types  of parameters.
     private int index;
     // the offset into the trigger method Object array of the initial value for this parameter
-    private int objectArrayIndex;
+    private int callArrayIndex;
     // the offset into the stack at which a local var is located
     private int localIndex;
+    private Binding alias; // aliases $x to $n where x is a method parameter name and n its index in the parameter list
 }

Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/compiler/Compiler.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/compiler/Compiler.java	2009-08-14 07:08:11 UTC (rev 28930)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/compiler/Compiler.java	2009-08-14 10:17:43 UTC (rev 28931)
@@ -254,6 +254,18 @@
         mv.visitVarInsn(ALOAD, 5);
         mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "getName", "()Ljava/lang/String;");
         mv.visitVarInsn(ASTORE, 6);
+        // if (binding.isAlias())
+        mv.visitVarInsn(ALOAD, 5);
+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "isAlias", "()Z");
+        Label l2a = new Label();
+        mv.visitJumpInsn(IFEQ, l2a);
+        // then
+        // binding = binding.getAlias();
+        mv.visitVarInsn(ALOAD, 5);
+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "getAlias", "()Lorg/jboss/byteman/rule/binding/Binding;");
+        mv.visitVarInsn(ASTORE, 5);
+        // endif
+        mv.visitLabel(l2a);
         // Type type = binding.getType();
         mv.visitVarInsn(ALOAD, 5);
         mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "getType", "()Lorg/jboss/byteman/rule/type/Type;");
@@ -313,13 +325,13 @@
         mv.visitJumpInsn(IFEQ, l4); // bypass this branch
         mv.visitLabel(l6);
         // then
-        // bindingMap.put(name, args[binding.getObjectArrayIndex]);
+        // bindingMap.put(name, args[binding.getCallArrayIndex]);
         mv.visitVarInsn(ALOAD, 0);
         mv.visitFieldInsn(GETFIELD, compiledHelperName, "bindingMap", "Ljava/util/HashMap;");
         mv.visitVarInsn(ALOAD, 6);
         mv.visitVarInsn(ALOAD, 3);
         mv.visitVarInsn(ALOAD, 5);
-        mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "getObjectArrayIndex", "()I");
+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/jboss/byteman/rule/binding/Binding", "getCallArrayIndex", "()I");
         mv.visitInsn(AALOAD);
         mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
         mv.visitInsn(POP);

Modified: labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/helper/InterpretedHelper.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/helper/InterpretedHelper.java	2009-08-14 07:08:11 UTC (rev 28930)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/src/org/jboss/byteman/rule/helper/InterpretedHelper.java	2009-08-14 10:17:43 UTC (rev 28931)
@@ -81,6 +81,11 @@
         while (iterator.hasNext()) {
             Binding binding = iterator.next();
             String name = binding.getName();
+            if (binding.isAlias()) {
+                // this is a local var used to refer to a method recipient or parameter
+                // so use the value and type associated with the alias
+                binding = binding.getAlias();
+            }
             Type type = binding.getType();
             if (binding.isHelper()) {
                 bindingMap.put(name, this);
@@ -89,7 +94,7 @@
                 bindingMap.put(name, recipient);
                 bindingTypeMap.put(name, type);
             } else if (binding.isParam() || binding.isLocalVar()) {
-                bindingMap.put(name, args[binding.getObjectArrayIndex()]);
+                bindingMap.put(name, args[binding.getCallArrayIndex()]);
                 bindingTypeMap.put(name, type);
             }
         }

Modified: labs/jbosstm/workspace/adinn/byteman/trunk/tests/build.xml
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/tests/build.xml	2009-08-14 07:08:11 UTC (rev 28930)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/tests/build.xml	2009-08-14 10:17:43 UTC (rev 28931)
@@ -407,6 +407,27 @@
           -->
           <test name="org.jboss.byteman.tests.bugfixes.TestEnclosedSynchronizationPropagation"/>
         </junit>
+        <junit fork="true" showoutput="true">
+          <classpath>
+              <pathelement location="${build.lib.dir}/byteman-tests.jar"/>
+              <pathelement location="${junit.home}/${junit.jar}"/>
+          </classpath>
+          <jvmarg value="-javaagent:${byteman.home}/${byteman.jar}=script:${scripts.dir}/bugfixes/TestMethodParamName.txt"/>
+          <!-- uncomment for verbose byteman output
+          <jvmarg value="-Dorg.jboss.byteman.verbose"/>
+          -->
+          <!-- uncomment to dump generated code
+          <jvmarg value="-Dorg.jboss.byteman.dump.generated.classes"/>
+          <jvmarg value="-Dorg.jboss.byteman.dump.generated.classes.directory=dump"/>
+          -->
+          <!-- uncomment to enable debug
+          <jvmarg value="-Xdebug"/>
+          <jvmarg  value="-Xnoagent"/>
+          <jvmarg  value="-Djava.compiler=NONE"/>
+          <jvmarg  value="-Xrunjdwp:transport=dt_socket,server=n,suspend=y,address=5005"/>
+          -->
+          <test name="org.jboss.byteman.tests.bugfixes.TestMethodParamName"/>
+        </junit>
   </target>
 
     <target name="tests.bugfixes.compiled">
@@ -457,6 +478,27 @@
           -->
           <test name="org.jboss.byteman.tests.bugfixes.TestEnclosedSynchronizationPropagation"/>
       </junit>
+        <junit fork="true" showoutput="true">
+          <classpath>
+              <pathelement location="${build.lib.dir}/byteman-tests.jar"/>
+              <pathelement location="${junit.home}/${junit.jar}"/>
+          </classpath>
+          <jvmarg value="-javaagent:${byteman.home}/${byteman.jar}=script:${scripts.dir}/bugfixes/TestMethodParamName.txt"/>
+          <jvmarg value="-Dorg.jboss.byteman.compileToBytecode"/>
+          <!-- uncomment for verbose byteman output
+          <jvmarg value="-Dorg.jboss.byteman.verbose"/>
+          -->
+          <!-- uncomment to dump generated code
+          <jvmarg value="-Dorg.jboss.byteman.dump.generated.classes"/>
+          <jvmarg value="-Dorg.jboss.byteman.dump.generated.classes.directory=dump"/>
+          -->
+          <!-- uncomment to enable debug
+          <jvmarg value="-Xdebug"/>
+          <jvmarg  value="-Xnoagent"/>
+          <jvmarg  value="-Djava.compiler=NONE"/>
+          <jvmarg  value="-Xrunjdwp:transport=dt_socket,server=n,suspend=y,address=5005"/>
+          -->
+          <test name="org.jboss.byteman.tests.bugfixes.TestMethodParamName"/>
+      </junit>
   </target>
-
 </project>

Added: labs/jbosstm/workspace/adinn/byteman/trunk/tests/dd/scripts/bugfixes/TestMethodParamName.txt
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/tests/dd/scripts/bugfixes/TestMethodParamName.txt	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/tests/dd/scripts/bugfixes/TestMethodParamName.txt	2009-08-14 10:17:43 UTC (rev 28931)
@@ -0,0 +1,34 @@
+##############################################################################
+# JBoss, Home of Professional Open Source
+# Copyright 2009, Red Hat Middleware LLC, and individual contributors
+# by the @authors tag. See the copyright.txt in the distribution for a
+# full listing of individual contributors.
+#
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this software; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+#
+# @authors Andrew Dinn
+#
+# Test for BYTEMAN-23 to ensure that a method parameter can be referred to
+# by its local variable name as well as using syntax $0, $1 etc
+
+RULE test use of method param names
+CLASS TestMethodParamName
+METHOD callWithNamedParams
+# HELPER org.jboss.byteman.tests.helpers.Default
+AT ENTRY
+IF TRUE
+DO test.log("injected foo() " + $this + " " + $bar + " " + $baz)
+ENDRULE

Added: labs/jbosstm/workspace/adinn/byteman/trunk/tests/src/org/jboss/byteman/tests/bugfixes/TestMethodParamName.java
===================================================================
--- labs/jbosstm/workspace/adinn/byteman/trunk/tests/src/org/jboss/byteman/tests/bugfixes/TestMethodParamName.java	                        (rev 0)
+++ labs/jbosstm/workspace/adinn/byteman/trunk/tests/src/org/jboss/byteman/tests/bugfixes/TestMethodParamName.java	2009-08-14 10:17:43 UTC (rev 28931)
@@ -0,0 +1,62 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat Middleware LLC, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*
+* @authors Andrew Dinn
+*/
+package org.jboss.byteman.tests.bugfixes;
+
+import org.jboss.byteman.tests.Test;
+
+/**
+ * Test to check that a script can refer to a method parameter by its name as well as using the
+ * $N syntax.
+ */
+public class TestMethodParamName extends Test
+{
+    public TestMethodParamName()
+    {
+        super(TestMethodParamName.class.getCanonicalName());
+    }
+
+    public void test()
+    {
+        try {
+            callWithNamedParams("bar", "baz");
+        } catch (Exception e) {
+            log(e);
+        }
+
+        checkOutput();
+    }
+
+    public void callWithNamedParams(String bar, String baz)
+    {
+        log("inside foo() " + this + " " + bar + " " + baz);
+    }
+
+    @Override
+    public String getExpected() {
+        logExpected("injected foo() " + this + " bar baz");
+        logExpected("inside foo() " + this + " bar baz");
+
+        return super.getExpected();
+    }
+}
\ No newline at end of file



More information about the jboss-svn-commits mailing list