/* * Copyright (c) 2016, 2018, 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 org.graalvm.compiler.microbenchmarks.lir; import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getGraph; import static org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil.getMethodFromMethodSpec; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.GraalCompiler; import org.graalvm.compiler.core.GraalCompiler.Request; import org.graalvm.compiler.core.LIRGenerationPhase; import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.gen.LIRCompilerBackend; import org.graalvm.compiler.core.gen.LIRGenerationProvider; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.lir.LIR; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; import org.graalvm.compiler.lir.phases.LIRPhase; import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; import org.graalvm.compiler.microbenchmarks.graal.util.GraalState; import org.graalvm.compiler.microbenchmarks.graal.util.GraalUtil; import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.tiers.TargetProvider; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.runtime.RuntimeProvider; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.SpeculationLog; /** * State providing a new copy of a graph for each invocation of a benchmark. Subclasses of this * class are annotated with {@link MethodSpec} to specify the Java method that will be parsed to * obtain the original graph. */ @State(Scope.Thread) public abstract class GraalCompilerState { /** * Original graph from which the per-benchmark invocation {@link #graph} is cloned. */ private StructuredGraph originalGraph; /** * The graph processed by the benchmark. */ private final OptionValues options; private final DebugContext debug; private StructuredGraph graph; private final Backend backend; private final Providers providers; /** * We only allow inner classes to subclass this to ensure that the {@link Setup} methods are * executed in the right order. */ @SuppressWarnings("try") protected GraalCompilerState() { this.options = Graal.getRequiredCapability(OptionValues.class); this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend(); this.providers = backend.getProviders(); this.debug = DebugContext.create(options, DebugHandlersFactory.LOADER); } protected boolean useProfilingInfo() { return false; } @SuppressWarnings("try") protected void initializeMethod() { GraalState graal = new GraalState(); ResolvedJavaMethod method = graal.metaAccess.lookupJavaMethod(getMethod()); StructuredGraph structuredGraph = null; try (DebugContext.Scope s = debug.scope("GraphState", method)) { structuredGraph = preprocessOriginal(getGraph(graal, method, useProfilingInfo())); } catch (Throwable t) { debug.handle(t); } this.originalGraph = structuredGraph; } protected Method getMethod() { Class> c = getClass(); if (isMethodSpecAnnotationPresent(c)) { return getMethodFromMethodSpec(c); } return findParamField(this); } protected boolean isMethodSpecAnnotationPresent(Class> startClass) { Class> c = startClass; while (c != null) { if (c.isAnnotationPresent(MethodSpec.class)) { return true; } c = c.getSuperclass(); } return false; } /** * Declares {@link GraalCompilerState#getMethodFromString(String) method description field}. The * field must be a {@link String} and have a {@link Param} annotation. */ @Inherited @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MethodDescString { } private static Method findParamField(Object obj) { Class> c = obj.getClass(); Class extends Annotation> annotationClass = MethodDescString.class; try { for (Field f : c.getFields()) { if (f.isAnnotationPresent(annotationClass)) { // these checks could be done by an annotation processor if (!f.getType().equals(String.class)) { throw new RuntimeException("Found a field annotated with " + annotationClass.getSimpleName() + " in " + c + " which is not a " + String.class.getSimpleName()); } if (!f.isAnnotationPresent(Param.class)) { throw new RuntimeException("Found a field annotated with " + annotationClass.getSimpleName() + " in " + c + " which is not annotated with " + Param.class.getSimpleName()); } String methodName; methodName = (String) f.get(obj); assert methodName != null; return getMethodFromString(methodName); } } } catch (Exception e) { throw new RuntimeException(e); } throw new RuntimeException("Could not find class annotated with " + annotationClass.getSimpleName() + " in hierarchy of " + c); } /** * Gets a {@link Method} from a method description string. The format is as follows: * *
* ClassName#MethodName * ClassName#MethodName(ClassName, ClassName, ...) ** *
CodeName
is passed to {@link Class#forName(String)}. * java.lang.String#equals * java.lang.String#equals(java.lang.Object) **/ protected static Method getMethodFromString(String methodDesc) { try { String[] s0 = methodDesc.split("#", 2); if (s0.length != 2) { throw new RuntimeException("Missing method description? " + methodDesc); } String className = s0[0]; Class> clazz = Class.forName(className); String[] s1 = s0[1].split("\\(", 2); String name = s1[0]; Class>[] parameters = null; if (s1.length > 1) { String parametersPart = s1[1]; if (parametersPart.charAt(parametersPart.length() - 1) != ')') { throw new RuntimeException("Missing closing ')'? " + methodDesc); } String[] s2 = parametersPart.substring(0, parametersPart.length() - 1).split(","); parameters = new Class>[s2.length]; for (int i = 0; i < s2.length; i++) { parameters[i] = Class.forName(s2[i]); } } return GraalUtil.getMethod(clazz, name, parameters); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) { return structuredGraph; } protected OptionValues getOptions() { return options; } protected Suites createSuites(OptionValues opts) { return backend.getSuites().getDefaultSuites(opts).copy(); } protected LIRSuites createLIRSuites(OptionValues opts) { return backend.getSuites().getDefaultLIRSuites(opts).copy(); } protected Backend getBackend() { return backend; } protected Providers getProviders() { return providers; } protected SnippetReflectionProvider getSnippetReflection() { return Graal.getRequiredCapability(SnippetReflectionProvider.class); } protected TargetDescription getTarget() { return getTargetProvider().getTarget(); } protected TargetProvider getTargetProvider() { return getBackend(); } protected CodeCacheProvider getCodeCache() { return getProviders().getCodeCache(); } protected ConstantReflectionProvider getConstantReflection() { return getProviders().getConstantReflection(); } protected MetaAccessProvider getMetaAccess() { return getProviders().getMetaAccess(); } protected LoweringProvider getLowerer() { return getProviders().getLowerer(); } protected PhaseSuite