diff options
7 files changed, 139 insertions, 63 deletions
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/jit/ByteCodeSwitch.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/jit/ByteCodeSwitch.java index 1ad77166..ce4f2b3d 100644 --- a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/jit/ByteCodeSwitch.java +++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/jit/ByteCodeSwitch.java @@ -11,13 +11,11 @@ package org.eclipse.m2m.atl.emftvm.jit; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -664,7 +662,7 @@ public class ByteCodeSwitch extends EmftvmSwitch<MethodVisitor> implements Opcod localVariable("body", CodeBlock.class, bodyStart, ifOpNull, bodyIdx); } // Generate native method invocation code here - final Method method = findRootMethod(object.getNativeMethod()); + final Method method = EMFTVMUtil.findRootMethod(object.getNativeMethod()); if (method != null) { // native method recorded - try first // Labels final Label subframeStart = new Label(); @@ -849,7 +847,7 @@ public class ByteCodeSwitch extends EmftvmSwitch<MethodVisitor> implements Opcod localVariable("body", CodeBlock.class, bodyStart, ifOpNull, bodyIdx); } // Generate native method invocation code here - final Method method = findRootMethod(object.getNativeMethod()); + final Method method = EMFTVMUtil.findRootMethod(object.getNativeMethod()); if (method != null) { // native method recorded - try first // Labels final Label subframeStart = new Label(); @@ -1085,61 +1083,6 @@ public class ByteCodeSwitch extends EmftvmSwitch<MethodVisitor> implements Opcod } /** - * Finds the root {@link Class} in which <code>method</code> was declared. - * @param method the method for which to find the root {@link Class} - * @return the root {@link Class} in which <code>method</code> was declared - */ - private Method findRootMethod(Method method) { - if (method == null) { - return null; - } - final int methodModifiers = getRelevantModifiers(method); - Class<?> dc = method.getDeclaringClass(); - java.util.Set<Class<?>> dis = new LinkedHashSet<Class<?>>( - Arrays.asList(dc.getInterfaces())); - while ((dc = dc.getSuperclass()) != null) { - try { - Method superMethod = dc.getDeclaredMethod(method.getName(), method.getParameterTypes()); - if (getRelevantModifiers(superMethod) == methodModifiers) { - method = superMethod; - } else { - break; - } - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - dis.addAll(Arrays.asList(dc.getInterfaces())); - } - while (!dis.isEmpty()) { - java.util.Set<Class<?>> newDis = new LinkedHashSet<Class<?>>(); - for (Class<?> di : dis) { - try { - // Only replace by method declared in a super-interface - if (di.isAssignableFrom(method.getDeclaringClass())) { - method = di.getDeclaredMethod(method.getName(), method.getParameterTypes()); - } - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - newDis.addAll(Arrays.asList(di.getInterfaces())); - } - newDis.removeAll(dis); - dis = newDis; - } - return method; - } - - /** - * Returns the relevant modifiers (visibility and static) for the given method. - * @param method the method for which to return the modifiers - * @return the relevant modifiers (visibility and static) for the given method - */ - private int getRelevantModifiers(final Method method) { - final int methodModifiers = method.getModifiers(); - return methodModifiers & (Modifier.PRIVATE + Modifier.PROTECTED + Modifier.PUBLIC + Modifier.STATIC); - } - - /** * {@inheritDoc} */ @Override diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java index d7a9164e..8365df2d 100644 --- a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java +++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/EMFTVMUtil.java @@ -1109,7 +1109,9 @@ public final class EMFTVMUtil { * the method arguments * @return the method result */ - public static Object invokeNative(final StackFrame frame, final Object self, final Method method, final Object[] args) { + public static Object invokeNative(final StackFrame frame, final Object self, Method method, final Object[] args) { + // Fix for Bug # 461445: EMFTVM cannot invoke Java methods on instances of private classes: + method = findRootMethod(method); final StackFrame subFrame = frame.prepareNativeArgs(method, self, args); try { return emf2vm(frame.getEnv(), self instanceof EObject ? (EObject) self : null, method.invoke(self, args)); @@ -1163,7 +1165,9 @@ public final class EMFTVMUtil { * the method argument * @return the method result */ - public static Object invokeNative(final StackFrame frame, final Object self, final Method method, Object arg) { + public static Object invokeNative(final StackFrame frame, final Object self, Method method, Object arg) { + // Fix for Bug # 461445: EMFTVM cannot invoke Java methods on instances of private classes: + method = findRootMethod(method); StackFrame subFrame = frame.prepareNativeContext(method, self); if (arg instanceof CodeBlock) { if (subFrame == null) { @@ -1220,7 +1224,9 @@ public final class EMFTVMUtil { * the method * @return the method result */ - public static Object invokeNative(final StackFrame frame, final Object self, final Method method) { + public static Object invokeNative(final StackFrame frame, final Object self, Method method) { + // Fix for Bug # 461445: EMFTVM cannot invoke Java methods on instances of private classes: + method = findRootMethod(method); final StackFrame subFrame = frame.prepareNativeContext(method, self); try { return emf2vm(frame.getEnv(), self instanceof EObject ? (EObject) self : null, method.invoke(self)); @@ -2425,4 +2431,59 @@ public final class EMFTVMUtil { } } + /** + * Finds the root {@link Class} declaration for the given <code>method</code>. + * @param method the method for which to find the root declaration + * @return the root {@link Method} + */ + public static Method findRootMethod(Method method) { + if (method == null) { + return null; + } + final int methodModifiers = getRelevantModifiers(method); + Class<?> dc = method.getDeclaringClass(); + java.util.Set<Class<?>> dis = new LinkedHashSet<Class<?>>( + Arrays.asList(dc.getInterfaces())); + while ((dc = dc.getSuperclass()) != null) { + try { + Method superMethod = dc.getDeclaredMethod(method.getName(), method.getParameterTypes()); + if (getRelevantModifiers(superMethod) == methodModifiers) { + method = superMethod; + } else { + break; + } + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } + dis.addAll(Arrays.asList(dc.getInterfaces())); + } + while (!dis.isEmpty()) { + java.util.Set<Class<?>> newDis = new LinkedHashSet<Class<?>>(); + for (Class<?> di : dis) { + try { + // Only replace by method declared in a super-interface + if (di.isAssignableFrom(method.getDeclaringClass())) { + method = di.getDeclaredMethod(method.getName(), method.getParameterTypes()); + } + } catch (SecurityException e) { + } catch (NoSuchMethodException e) { + } + newDis.addAll(Arrays.asList(di.getInterfaces())); + } + newDis.removeAll(dis); + dis = newDis; + } + return method; + } + + /** + * Returns the relevant modifiers (visibility and static) for the given method. + * @param method the method for which to return the modifiers + * @return the relevant modifiers (visibility and static) for the given method + */ + private static int getRelevantModifiers(final Method method) { + final int methodModifiers = method.getModifiers(); + return methodModifiers & (Modifier.PRIVATE + Modifier.PROTECTED + Modifier.PUBLIC + Modifier.STATIC); + } + } diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug461445.launch b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug461445.launch new file mode 100644 index 00000000..6b308e80 --- /dev/null +++ b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug461445.launch @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.m2m.atl.emftvm.launcher.EMFTVMTransformation"> +<stringAttribute key="ATL File Name" value="//org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.atl"/> +<booleanAttribute key="Disable JIT compiler" value="false"/> +<booleanAttribute key="Display Profiling Data" value="false"/> +<booleanAttribute key="Display Timing Data" value="true"/> +<mapAttribute key="Inout Model Options"/> +<mapAttribute key="Inout Models"/> +<mapAttribute key="Inout Models Output Locations"/> +<mapAttribute key="Input Model Options"/> +<mapAttribute key="Input Models"/> +<mapAttribute key="Metamodel Options"/> +<mapAttribute key="Metamodels"/> +<stringAttribute key="Module Name" value="Regression::Bug461445"/> +<stringAttribute key="Module Path" value="/org.eclipse.m2m.atl.emftvm.tests/test-data/"/> +<mapAttribute key="Output Model Options"/> +<mapAttribute key="Output Models"/> +<listAttribute key="Superimpose"/> +</launchConfiguration> diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/launch/EmftvmAllTests.launch b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/EmftvmAllTests.launch index 836b1d6e..48a62148 100644 --- a/tests/org.eclipse.m2m.atl.emftvm.tests/launch/EmftvmAllTests.launch +++ b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/EmftvmAllTests.launch @@ -24,7 +24,7 @@ <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> -<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/java-1.7.0-openjdk-1.7.0.71-2.5.3.0.fc19.x86_64"/> +<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.m2m.atl.emftvm.tests.EmftvmAllTests"/> <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.m2m.atl.emftvm.tests"/> diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java index 537d20ac..ab79a88d 100644 --- a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java +++ b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java @@ -11,14 +11,24 @@ *******************************************************************************/ package org.eclipse.m2m.atl.emftvm.tests.integration; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.logging.Level; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.m2m.atl.common.ATLLogger; +import org.eclipse.m2m.atl.core.ATLCoreException; +import org.eclipse.m2m.atl.core.IModel; +import org.eclipse.m2m.atl.core.IReferenceModel; +import org.eclipse.m2m.atl.core.ModelFactory; import org.eclipse.m2m.atl.emftvm.EmftvmFactory; import org.eclipse.m2m.atl.emftvm.EmftvmPackage; import org.eclipse.m2m.atl.emftvm.ExecEnv; @@ -28,6 +38,7 @@ import org.eclipse.m2m.atl.emftvm.tests.EMFTVMTest; import org.eclipse.m2m.atl.emftvm.trace.TracePackage; import org.eclipse.m2m.atl.emftvm.util.LazyList; import org.eclipse.m2m.atl.emftvm.util.TimingData; +import org.eclipse.m2m.atl.engine.parser.AtlParser; /** * @author <a href="dwagelaar@gmail.com">Dennis Wagelaar</a> @@ -360,6 +371,44 @@ public class IntegrationTest extends EMFTVMTest { } /** + * Tests regression of <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=461445">Bug # 461445</a>. + */ + public void testBug461445() { + final ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv(); + final TimingData td = new TimingData(); + env.loadModule(createTestModuleResolver(), "Regression::Bug461445"); + td.finishLoading(); + final Object result = env.run(td); + td.finish(); + + assertEquals("value", result); + } + + public void testATLAPI() throws ATLCoreException, IOException { + + ModelFactory mf = AtlParser.getDefault().getModelFactory(); + IReferenceModel atlMM = AtlParser.getDefault().getAtlMetamodel(); + IModel atlM = mf.newModel(atlMM); + + EObject module = (EObject) atlM.newElement(atlMM.getMetaElementByName("Module")); + module.eSet(module.eClass().getEStructuralFeature("name"), "testmodule"); + EObject rule = (EObject) atlM.newElement(atlMM.getMetaElementByName("MatchedRule")); + rule.eSet(rule.eClass().getEStructuralFeature("name"), "Test"); + EList<EObject> moduleElements = (EList<EObject>) module.eGet(module.eClass().getEStructuralFeature("elements")); + moduleElements.add(rule); + + FileOutputStream fos = new FileOutputStream("testmodule.atl"); + try { + AtlParser.getDefault().extract(atlM, fos, Collections.emptyMap()); + } finally { + if (fos != null) { + fos.close(); + } + } + + } + + /** * Tests "ToStringTest.atl". */ public void testToString() { diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.atl b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.atl new file mode 100644 index 00000000..6fb9e980 --- /dev/null +++ b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.atl @@ -0,0 +1,4 @@ +-- @atlcompiler emftvm +query "Regression::Bug461445" = "#native"!"java::util::Collections" + .refInvokeStaticOperation('unmodifiableMap', Sequence{Map{('key', 'value')}}) + .get('key').debug('Bug'); diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.emftvm b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.emftvm Binary files differnew file mode 100644 index 00000000..88f4dc95 --- /dev/null +++ b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug461445.emftvm |