# HG changeset patch # User Christos Kotselidis # Date 1366232376 -7200 # Node ID c433aad055b987a00fec737cee9de7af4963aaca # Parent e1f024e025976307b12f0b5398adb6aa8b2f04f5# Parent 4e6df9021a59ebc60f376de6060e4b416d1fe39f Merge diff -r e1f024e02597 -r c433aad055b9 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Wed Apr 17 22:58:51 2013 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Wed Apr 17 22:59:36 2013 +0200 @@ -22,12 +22,18 @@ */ package com.oracle.graal.compiler.test; +import java.io.*; import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; import org.junit.*; import com.oracle.graal.api.code.*; +import com.oracle.graal.api.code.Assumptions.Assumption; +import com.oracle.graal.api.code.Assumptions.NoFinalizableSubclass; import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; @@ -36,21 +42,19 @@ public class FinalizableSubclassTest extends GraalCompilerTest { - public static class NoFinalizerEver { - + /** + * used as template to generate class files at runtime. + */ + public static class NoFinalizerEverAAAA { } - public static class NoFinalizerYet { - + public static class NoFinalizerYetAAAA { } - public static class WithFinalizer extends NoFinalizerYet { - - static int someCounter = 0; + public static class WithFinalizerAAAA extends NoFinalizerYetAAAA { @Override protected void finalize() throws Throwable { - someCounter++; super.finalize(); } } @@ -72,17 +76,129 @@ Assumptions assumptions = new Assumptions(optimistic); StructuredGraph graph = parseAndProcess(cl, assumptions); Assert.assertTrue(graph.getNodes().filter(RegisterFinalizerNode.class).count() == (shouldContainFinalizer ? 1 : 0)); + int noFinalizerAssumption = 0; + for (Assumption a : assumptions) { + if (a instanceof NoFinalizableSubclass) { + noFinalizerAssumption++; + } + } + Assert.assertTrue(noFinalizerAssumption == (shouldContainFinalizer ? 0 : 1)); + } + + /** + * Use a custom class loader to generate classes, to make sure the given classes are loaded in + * correct order. + */ + @Test + public void test1() throws ClassNotFoundException { + for (int i = 0; i < 2; i++) { + ClassTemplateLoader loader = new ClassTemplateLoader(); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, false); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, true); + + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, true); + + checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, true); + checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, true); + } } - @Test - public void test1() { - checkForRegisterFinalizeNode(NoFinalizerEver.class, true, false); - checkForRegisterFinalizeNode(NoFinalizerEver.class, false, true); + private static class ClassTemplateLoader extends ClassLoader { + + private static int loaderInstance = 0; + + private final String replaceTo; + private HashMap cache = new HashMap<>(); + + public ClassTemplateLoader() { + loaderInstance++; + replaceTo = String.format("%04d", loaderInstance); + } + + @Override + protected Class findClass(final String name) throws ClassNotFoundException { + return Debug.scope("FinalizableSubclassTest", new Callable>() { + + @Override + public Class call() throws Exception { + String nameReplaced = name.replaceAll("AAAA", replaceTo); + if (cache.containsKey(nameReplaced)) { + return cache.get(nameReplaced); + } + + // copy classfile to byte array + byte[] classData = null; + try { + InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class"); + assert is != null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + byte[] buf = new byte[1024]; + int size; + while ((size = is.read(buf, 0, buf.length)) != -1) { + baos.write(buf, 0, size); + } + baos.flush(); + classData = baos.toByteArray(); + } catch (IOException e) { + Assert.fail("can't access class: " + name); + } + dumpStringsInByteArray(classData); + + // replace all occurrences of "AAAA" in classfile + int index = -1; + while ((index = indexOfAAAA(classData, index + 1)) != -1) { + replaceAAAA(classData, index, replaceTo); + } + dumpStringsInByteArray(classData); - // fails if WithFinalizer is already loaded (e.g. on a second execution of this test) - checkForRegisterFinalizeNode(NoFinalizerYet.class, false, true); + Class c = defineClass(null, classData, 0, classData.length); + cache.put(nameReplaced, c); + return c; + } + }); + } + + private static int indexOfAAAA(byte[] b, int index) { + for (int i = index; i < b.length; i++) { + boolean match = true; + for (int j = i; j < i + 4; j++) { + if (b[j] != (byte) 'A') { + match = false; + break; + } + } + if (match) { + return i; + } + } + return -1; + } - checkForRegisterFinalizeNode(WithFinalizer.class, true, true); - checkForRegisterFinalizeNode(NoFinalizerYet.class, true, true); + private static void replaceAAAA(byte[] b, int index, String replacer) { + assert replacer.length() == 4; + for (int i = index; i < index + 4; i++) { + b[i] = (byte) replacer.charAt(i - index); + } + } + + private static void dumpStringsInByteArray(byte[] b) { + boolean wasChar = true; + StringBuilder sb = new StringBuilder(); + for (Byte x : b) { + // check for [a-zA-Z0-9] + if ((x >= 0x41 && x <= 0x7a) || (x >= 0x30 && x <= 0x39)) { + if (!wasChar) { + Debug.log(sb + ""); + sb.setLength(0); + } + sb.append(String.format("%c", x)); + wasChar = true; + } else { + wasChar = false; + } + } + Debug.log(sb + ""); + } } } diff -r e1f024e02597 -r c433aad055b9 make/build-graal.xml --- a/make/build-graal.xml Wed Apr 17 22:58:51 2013 +0200 +++ b/make/build-graal.xml Wed Apr 17 22:59:36 2013 +0200 @@ -31,7 +31,7 @@ - + diff -r e1f024e02597 -r c433aad055b9 mx/commands.py --- a/mx/commands.py Wed Apr 17 22:58:51 2013 +0200 +++ b/mx/commands.py Wed Apr 17 22:59:36 2013 +0200 @@ -468,7 +468,7 @@ out.open('target', {'name' : 'compile', 'depends' : 'cleanclasses'}) out.element('mkdir', {'dir' : '${classes.dir}'}) - out.open('javac', {'destdir' : '${classes.dir}', 'debug' : 'on', 'includeantruntime' : 'false', 'encoding' : 'UTF-8'}) + out.open('javac', {'destdir' : '${classes.dir}', 'debug' : 'on', 'includeantruntime' : 'false', }) for p in mx.sorted_deps(mx.distribution('GRAAL').deps): out.element('src', {'path' : '${src.dir}/' + p.name}) diff -r e1f024e02597 -r c433aad055b9 mx/sanitycheck.py --- a/mx/sanitycheck.py Wed Apr 17 22:58:51 2013 +0200 +++ b/mx/sanitycheck.py Wed Apr 17 22:59:36 2013 +0200 @@ -224,19 +224,8 @@ Full, NoInline, NoComplex = range(3) def getCTW(vm,mode): - - modeString = '' - if mode == CTWMode.Full: - modeString = 'Full' - elif mode == CTWMode.NoInline: - modeString = 'NoInline' - elif mode == CTWMode.NoComplex: - modeString = 'NoComplex' - else: - mx.abort("Unknown CTW mode") - time = re.compile(r"CompileTheWorld : Done \([0-9]+ classes, [0-9]+ methods, (?P