Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 3 commits
  • 7 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 26, 2012
@adinn Changed method typecheck algorithm for non-builtins so that it
considers each class and interface in the class hierarchy as a
candidate for a matching method. Previously only class methods were
considered which meant that a call to an (undefined) interface method
of an abstract class was failing with a method not found error even
though there is guaranteed to be an actual implementation of that
method at runtime. fixes BYTEMAN-219
d075777
@adinn added test case for
fixed problem with method compilation where it was planting an
invokevirtual where invokeinterface was needed

fixes for BYTEMAN-219
19c2683
@adinn new files for fix to BYTEMAN-219 29c9870
View
30 agent/pom.xml
@@ -779,6 +779,21 @@
<argLine>-javaagent:${project.build.directory}/byteman-${project.version}.jar=script:${project.build.testOutputDirectory}/scripts/bugfixes/TestAfterCallAssign.btm</argLine>
</configuration>
</execution>
+ <execution>
+ <id>bugfixes.TestAbstractInterfaceCall</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <forkMode>once</forkMode>
+ <includes>
+ <include>org/jboss/byteman/tests/bugfixes/TestAbstractInterfaceCall.class</include>
+ </includes>
+ <argLine>-javaagent:${project.build.directory}/byteman-${project.version}.jar=script:${project.build.testOutputDirectory}/scripts/bugfixes/TestAbstractInterfaceCall.btm</argLine>
+ </configuration>
+ </execution>
<!-- dynamic rule submission
n.b. submit test does not use a script on the command line
instead it sets listener true and uplaods the rules from the test program
@@ -1464,6 +1479,21 @@
<argLine>-Dorg.jboss.byteman.compile.to.bytecode -javaagent:${project.build.directory}/byteman-${project.version}.jar=script:${project.build.testOutputDirectory}/scripts/bugfixes/TestAfterCallAssign.btm</argLine>
</configuration>
</execution>
+ <execution>
+ <id>bugfixes.TestAbstractInterfaceCall.compiled</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <forkMode>once</forkMode>
+ <includes>
+ <include>org/jboss/byteman/tests/bugfixes/TestAbstractInterfaceCall.class</include>
+ </includes>
+ <argLine>-Dorg.jboss.byteman.compile.to.bytecode -javaagent:${project.build.directory}/byteman-${project.version}.jar=script:${project.build.testOutputDirectory}/scripts/bugfixes/TestAbstractInterfaceCall.btm</argLine>
+ </configuration>
+ </execution>
<!-- dynamic rule submission compiled
submit test does not use a script on the command line
instead it sets listener true and uplaods the rules from the test program
View
45 agent/src/main/java/org/jboss/byteman/rule/expression/MethodExpression.java
@@ -36,6 +36,7 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import java.util.LinkedList;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
@@ -205,9 +206,41 @@ private void findMethod(boolean publicOnly) throws TypeException
boolean isStatic = (recipient == null);
int arity = arguments.size();
- while (clazz != null) {
+ LinkedList<Class<?>> clazzes = new LinkedList<Class<?>>();
+ if (publicOnly) {
+ // we can use getDeclaredMethods on just one class to list all possible candidates
+ clazzes.add(clazz);
+ } else {
+ // we need to iterate over the class and interface hierarchy bottom up
+ while (clazz != null) {
+ clazzes.add(clazz);
+ // collect all direct interfaces in order
+ Class[] ifaces = clazz.getInterfaces();
+ LinkedList<Class<?>> toBeChecked = new LinkedList<Class<?>>();
+ for (int i = 0; i < ifaces.length; i++) {
+ toBeChecked.addLast(ifaces[i]);
+ }
+ // process each interface in turn, also collecting its parent interfaces for consideration
+ while (!toBeChecked.isEmpty()) {
+ Class<?> iface = toBeChecked.pop();
+ // only need to process it if we have not already seen it
+ if (!clazzes.contains(iface)) {
+ clazzes.addLast(iface);
+ Class[] ifaces2 = iface.getInterfaces();
+ // don't bother to check for repeats here as we check later anyway
+ for (int j = 0; j < ifaces2.length; j++) {
+ toBeChecked.addLast(ifaces2[j]);
+ }
+ }
+ }
+ // move on to the next class
+ clazz = clazz.getSuperclass();
+ }
+ }
+ // now check for a matching method in each class or interface in order
+ while (!clazzes.isEmpty()) {
+ clazz = clazzes.pop();
List<Method> candidates = new ArrayList<Method>();
- Class<?> superClazz = clazz.getSuperclass();
try {
Method[] methods;
if (publicOnly) {
@@ -280,12 +313,6 @@ private void findMethod(boolean publicOnly) throws TypeException
} catch (SecurityException e) {
// continue in case we can find an implementation
}
-
- if (publicOnly) {
- clazz = null;
- } else {
- clazz = superClazz;
- }
}
// no more possible candidates so throw up here
@@ -386,7 +413,7 @@ public void compile(MethodVisitor mv, CompileContext compileContext) throws Comp
if (recipient == null) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, ownerName, method.getName(), getDescriptor());
- } else if (recipient.getClass().isInterface()) {
+ } else if (method.getDeclaringClass().isInterface()) {
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, ownerName, method.getName(), getDescriptor());
} else {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ownerName, method.getName(), getDescriptor());
View
40 agent/src/test/java/org/jboss/byteman/tests/auxiliary/C3.java
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, Red Hat 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.auxiliary;
+
+import org.jboss.byteman.tests.Test;
+
+/**
+ * test class for fix to BYTEMAN-219
+ */
+public abstract class C3 implements I5
+{
+ // n.b. this class does not implement interfaceMethod() inherited from I5
+ // but it's instantiable subclasses always will!
+ public void testMethod(Test test)
+ {
+ test.log("inside C3.testMethod");
+ }
+}
View
39 agent/src/test/java/org/jboss/byteman/tests/auxiliary/C4.java
@@ -0,0 +1,39 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, Red Hat 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.auxiliary;
+
+import org.jboss.byteman.tests.Test;
+
+/**
+ * test class for fix to BYTEMAN-219
+ */
+public class C4 extends C3
+{
+ // this non-abstract class has to implement interfaceMethod() inherited from I5 via C3
+ public void interfaceMethod(Test test)
+ {
+ test.log("inside C4.interfaceMethod");
+ }
+}
View
35 agent/src/test/java/org/jboss/byteman/tests/auxiliary/I5.java
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011, Red Hat 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.auxiliary;
+
+import org.jboss.byteman.tests.Test;
+
+/**
+ * test class for fix to BYTEMAN-219
+ */
+public interface I5
+{
+ public void interfaceMethod(Test test);
+}
View
67 agent/src/test/java/org/jboss/byteman/tests/bugfixes/TestAbstractInterfaceCall.java
@@ -0,0 +1,67 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2012, Red Hat 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;
+import org.jboss.byteman.tests.auxiliary.C3;
+import org.jboss.byteman.tests.auxiliary.C4;
+import org.jboss.byteman.tests.auxiliary.I5;
+
+
+/**
+ * Test for BYTEMAN-219 where a call to an interface method of an abstract class failed to typecheck
+ * because there was no implementation on the abstract class.
+ */
+public class TestAbstractInterfaceCall extends Test
+{
+ private int run;
+
+ public TestAbstractInterfaceCall()
+ {
+ super(TestAbstractInterfaceCall.class.getCanonicalName());
+ }
+
+ public void test()
+ {
+ C4 c4 = new C4();
+ try {
+ log("calling C4.testMethod");
+ c4.testMethod(this);
+ log("called C4.testMethod");
+ } catch (Exception e) {
+ log(e);
+ }
+
+ checkOutput(true);
+ }
+
+ @Override
+ public String getExpected() {
+ logExpected("calling C4.testMethod");
+ logExpected("inside C4.interfaceMethod");
+ logExpected("inside C3.testMethod");
+ logExpected("called C4.testMethod");
+ return super.getExpected();
+ }
+}
View
42 agent/src/test/resources/scripts/bugfixes/TestAbstractInterfaceCall.btm
@@ -0,0 +1,42 @@
+##############################################################################
+# JBoss, Home of Professional Open Source
+# Copyright 2009, Red Hat 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-219 to ensure that it is possible to call an interface method
+# inherited by an abstract class even if the abstract class does not iself
+# implement the method. the interface method will always be defined by any
+# instantiable subclass so a call to the method should typecheck ands execute
+# correctly.
+#
+# in this example C3 is an abstract class which implements interface I4
+# but leaves it to its subclass C4 to provide the actual implementation of
+# method interfaceMethod. The type checker should still detect that this
+# method can safely be called on any instance of C3.
+
+RULE test abstract interface method call
+CLASS C3
+METHOD testMethod(Test)
+HELPER org.jboss.byteman.tests.helpers.Default
+BIND test : TestAbstractInterfaceCall = $1
+IF TRUE
+DO $0.interfaceMethod(test)
+ENDRULE

No commit comments for this range

Something went wrong with that request. Please try again.