Mercurial > hg > graal-compiler
changeset 22779:f054c4a8e6b2
Unit test for lazy initialization of Graal.
author | Roland Schatz <roland.schatz@oracle.com> |
---|---|
date | Thu, 08 Oct 2015 15:08:36 +0200 |
parents | 60d59d17d419 |
children | 5b5bcde5a0de |
files | graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/LazyInitializationTest.java |
diffstat | 1 files changed, 192 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/LazyInitializationTest.java Thu Oct 08 15:08:36 2015 +0200 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015, 2015, 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.truffle.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +import jdk.internal.jvmci.compiler.CompilerFactory; +import jdk.internal.jvmci.options.OptionDescriptor; +import jdk.internal.jvmci.options.OptionDescriptors; +import jdk.internal.jvmci.options.OptionValue; + +import org.junit.Assert; +import org.junit.Test; + +import com.oracle.graal.compiler.CompilerThreadFactory; +import com.oracle.graal.test.SubprocessUtil; + +/** + * Test lazy initialization of Graal in the context of Truffle. When simply executing Truffle code, + * Graal should not be initialized unless there is an actual compilation request. + */ +public class LazyInitializationTest { + + private final Class<?> hotSpotVMEventListener; + private final Class<?> hotSpotGraalCompilerFactoryOptions; + + public LazyInitializationTest() { + hotSpotVMEventListener = forNameOrNull("jdk.internal.jvmci.hotspot.HotSpotVMEventListener"); + hotSpotGraalCompilerFactoryOptions = forNameOrNull("com.oracle.graal.hotspot.HotSpotGraalCompilerFactory$Options"); + } + + private static Class<?> forNameOrNull(String name) { + try { + return Class.forName(name); + } catch (ClassNotFoundException e) { + return null; + } + } + + @Test + public void testSLTck() throws IOException, InterruptedException { + spawnUnitTests("com.oracle.truffle.sl.test.SLTckTest"); + } + + /** + * Spawn a new VM, execute unit tests, and check which classes are loaded. + */ + private void spawnUnitTests(String... tests) throws IOException, InterruptedException { + ArrayList<String> args = new ArrayList<>(SubprocessUtil.getVMCommandLine()); + + int jvmciArg = args.indexOf("-jvmci"); + if (jvmciArg >= 0) { + args.set(jvmciArg, "-server"); + } + + args.add("-XX:+TraceClassLoading"); + args.add("com.oracle.mxtool.junit.MxJUnitWrapper"); + args.addAll(Arrays.asList(tests)); + + ArrayList<Class<?>> loadedGraalClasses = new ArrayList<>(); + + Process process = new ProcessBuilder(args).start(); + + int testCount = 0; + BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = stdout.readLine()) != null) { + if (line.startsWith("[Loaded ")) { + int start = "[Loaded ".length(); + int end = line.indexOf(' ', start); + String loadedClass = line.substring(start, end); + if (isGraalClass(loadedClass)) { + try { + loadedGraalClasses.add(Class.forName(loadedClass)); + } catch (ClassNotFoundException e) { + Assert.fail("loaded class " + loadedClass + " not found"); + } + } + } else if (line.startsWith("OK (")) { + Assert.assertTrue(testCount == 0); + int start = "OK (".length(); + int end = line.indexOf(' ', start); + testCount = Integer.parseInt(line.substring(start, end)); + } + } + + Assert.assertNotEquals("test count", 0, testCount); + Assert.assertEquals("exit code", 0, process.waitFor()); + + checkAllowedGraalClasses(loadedGraalClasses); + } + + private static boolean isGraalClass(String className) { + if (className.startsWith("com.oracle.graal.truffle.")) { + // Ignore classes in the com.oracle.graal.truffle package, they are all allowed. + return false; + } else { + return className.startsWith("com.oracle.graal."); + } + } + + private void checkAllowedGraalClasses(List<Class<?>> loadedGraalClasses) { + HashSet<Class<?>> whitelist = new HashSet<>(); + + /* + * Look for all loaded OptionDescriptors classes, and whitelist the classes that declare the + * options. They may be loaded by the option parsing code. + */ + for (Class<?> cls : loadedGraalClasses) { + if (OptionDescriptors.class.isAssignableFrom(cls)) { + try { + OptionDescriptors optionDescriptors = cls.asSubclass(OptionDescriptors.class).newInstance(); + for (OptionDescriptor option : optionDescriptors) { + whitelist.add(option.getDeclaringClass()); + } + } catch (ReflectiveOperationException e) { + } + } + } + + for (Class<?> cls : loadedGraalClasses) { + if (whitelist.contains(cls)) { + continue; + } + + if (!isGraalClassAllowed(cls)) { + Assert.fail("loaded class: " + cls.getName()); + } + } + } + + private boolean isGraalClassAllowed(Class<?> cls) { + if (CompilerThreadFactory.class.equals(cls) || CompilerThreadFactory.DebugConfigAccess.class.equals(cls)) { + // The HotSpotTruffleRuntime creates a CompilerThreadFactory for Truffle. + return true; + } + + if (cls.equals(hotSpotGraalCompilerFactoryOptions)) { + // The JVMCI initialization code needs to accesses an option defined in this class. + return true; + } + + if (CompilerFactory.class.isAssignableFrom(cls)) { + // The compiler factories have to be loaded and instantiated by the JVMCI. + return true; + } + + if (OptionDescriptors.class.isAssignableFrom(cls)) { + // If options are specified, the corresponding *_OptionDescriptors classes are loaded. + return true; + } + + if (OptionValue.class.isAssignableFrom(cls)) { + // If options are specified, that may implicitly load a custom OptionValue subclass. + return true; + } + + if (hotSpotVMEventListener != null && hotSpotVMEventListener.isAssignableFrom(cls)) { + // HotSpotVMEventListeners need to be loaded on JVMCI startup. + return true; + } + + // No other class from the com.oracle.graal package should be loaded. + return false; + } +}