# HG changeset patch # User Thomas Wuerthinger # Date 1339689299 -7200 # Node ID 4967be7265bc663073513951d3ff10ef2ad94291 # Parent 102f87543d5e2a3e8ec91fd720c08aa33e474227 Added BootImageClassLoader and associated test class. diff -r 102f87543d5e -r 4967be7265bc graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/BootImageClassLoaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/BootImageClassLoaderTest.java Thu Jun 14 17:54:59 2012 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.boot; + +import java.lang.reflect.*; + +import org.junit.*; + + +public class BootImageClassLoaderTest { + + @Test + public void test() throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, SecurityException { + + TestClassB.x = 1; + BootImageClassLoader l = new BootImageClassLoader(); + + // Assert that the class definition is really duplicated. + Class bClass = Class.forName(TestClassB.class.getCanonicalName(), true, l); + Assert.assertNotSame(TestClassB.class, bClass); + + // Assert that the class definition is not duplicated more than once. + Assert.assertSame(bClass, l.convert(TestClassB.class)); + + // Set field x such that it is used by the subsequent static initializer for TestClassA. + Field bField = bClass.getFields()[0]; + bField.setAccessible(true); + bField.set(null, 2); + + // Assert that the class definition is duplicated. + Class aClass = l.convert(TestClassA.class); + Assert.assertNotSame(TestClassA.class, aClass); + + // Assert that the original version of TestClassA was initialized correctly. + Assert.assertEquals(1, TestClassA.x); + + // Assert that the duplicated version of TestClassA was initialized correctly. + Field aField = aClass.getFields()[0]; + aField.setAccessible(true); + Assert.assertEquals(2, aField.getInt(null)); + + // Assert that system classes are not duplicated. + Assert.assertSame(Object.class, l.convert(Object.class)); + Assert.assertSame(Object.class, Class.forName(Object.class.getCanonicalName(), true, l)); + } + +} + +class TestClassA { + public static int x; + + static { + x = TestClassB.x; + } +} + +class TestClassB { + public static int x; +} diff -r 102f87543d5e -r 4967be7265bc graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/HelloWorldTest.java --- a/graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/HelloWorldTest.java Mon Jun 11 17:06:06 2012 +0200 +++ b/graal/com.oracle.graal.boot.test/src/com/oracle/graal/boot/HelloWorldTest.java Thu Jun 14 17:54:59 2012 +0200 @@ -22,7 +22,25 @@ */ package com.oracle.graal.boot; +import java.io.*; +import java.lang.reflect.*; + +import com.oracle.graal.boot.test.helloworld.*; + public class HelloWorldTest { + public static void main(String[] args) throws NoSuchMethodException, SecurityException, IOException { + Method entryPoint = HelloWorldTestProgram.class.getMethod("main", String[].class); + System.out.println(HelloWorldTestProgram.class.getCanonicalName()); + InputStream inputStream = HelloWorldTestProgram.class.getClassLoader().getResourceAsStream(HelloWorldTestProgram.class.getName().replace('.', '/').concat(".class")); + byte[] byteCodes = new byte[inputStream.available()]; + inputStream.read(byteCodes); + System.out.println(byteCodes); + ClassLoader l = new ClassLoader() { + + + }; + + } } diff -r 102f87543d5e -r 4967be7265bc graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageClassLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageClassLoader.java Thu Jun 14 17:54:59 2012 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.boot; + +import java.io.*; + +public class BootImageClassLoader extends ClassLoader { + + @Override + protected java.lang.Class< ? > loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock(name)) { + Class< ? > result = findLoadedClass(name); + if (result == null) { + result = super.loadClass(name, resolve); + assert result.getName().equals(name); + return duplicate(result); + } + return result; + } + } + + private Class< ? > duplicate(Class< ? > result) { + // This is a class in the bootclasspath => share. + if (result.getClassLoader() == null) { + return result; + } + + // Duplicate class definition. + InputStream inputStream = result.getClassLoader().getResourceAsStream(result.getName().replace('.', '/').concat(".class")); + try { + byte[] byteCodes = new byte[inputStream.available()]; + inputStream.read(byteCodes); + return this.defineClass(result.getName(), byteCodes, 0, byteCodes.length); + } catch (IOException e) { + throw new RuntimeException("Could not access class bytes for " + result.getName()); + } + } + + public Class< ? > convert(Class< ? > clazz) { + synchronized (getClassLoadingLock(clazz.getCanonicalName())) { + // This class has this class loader => no conversion necessary. + if (clazz.getClassLoader() == this) { + return clazz; + } + + Class< ? > thisClazz = findLoadedClass(clazz.getName()); + if (thisClazz != null) { + return thisClazz; + } + + return duplicate(clazz); + } + } +} diff -r 102f87543d5e -r 4967be7265bc graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageGenerator.java --- a/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageGenerator.java Mon Jun 11 17:06:06 2012 +0200 +++ b/graal/com.oracle.graal.boot/src/com/oracle/graal/boot/BootImageGenerator.java Thu Jun 14 17:54:59 2012 +0200 @@ -22,7 +22,24 @@ */ package com.oracle.graal.boot; +import java.lang.reflect.*; + +import com.oracle.graal.debug.*; + public class BootImageGenerator { + private final BootImageClassLoader classLoader = new BootImageClassLoader(); + + public void addEntryMethod(Class clazz, String name, Class ... parameterTypes) { + Class convertedClass = classLoader.convert(clazz); + Method method; + try { + method = convertedClass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("Could not find method " + name + " with parameter types " + parameterTypes + " in class " + convertedClass.getCanonicalName()); + } + Debug.log("Adding method %s.%s to the boot image", method.getClass().getName(), method.getName()); + } + }