changeset 12529:23dc5dfdb9c7

Add OptimizedCallTarget.call(PackedFrame, Arguments) frame prologue injection
author Matthias Grimmer <grimmer@ssw.jku.at>
date Tue, 22 Oct 2013 13:25:37 +0200
parents 9fe4cd9d7e12
children ecd85445f77a
files graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64HotSpotTruffleBackend.java graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java
diffstat 4 files changed, 168 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64HotSpotTruffleBackend.java	Tue Oct 22 13:24:43 2013 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64HotSpotTruffleBackend.java	Tue Oct 22 13:25:37 2013 +0200
@@ -22,16 +22,20 @@
  */
 package com.oracle.graal.truffle.hotspot.amd64;
 
+import com.oracle.graal.amd64.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.amd64.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.truffle.*;
+import com.oracle.graal.truffle.hotspot.amd64.util.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 
@@ -63,7 +67,32 @@
     protected void emitCodePrefix(ResolvedJavaMethod installedCodeOwner, TargetMethodAssembler tasm, AMD64MacroAssembler asm, RegisterConfig regConfig, HotSpotVMConfig config, Label verifiedStub) {
         super.emitCodePrefix(installedCodeOwner, tasm, asm, regConfig, config, verifiedStub);
         if (getInstrumentedMethod().equals(installedCodeOwner)) {
-            // TODO emit tailcall code
+            HotSpotProviders providers = getRuntime().getHostProviders();
+            Register thisRegister = providers.getCodeCache().getRegisterConfig().getCallingConventionRegisters(Type.JavaCall, Kind.Object)[0];
+            Register spillRegister = AMD64.r10; // TODO(mg): fix me
+            AMD64Address nMethodAddress = new AMD64Address(thisRegister, OptimizedCallTargetFieldInfo.getCompiledMethodFieldOffset());
+            if (config.useCompressedOops) {
+                asm.movl(spillRegister, nMethodAddress);
+                AMD64HotSpotMove.decodePointer(asm, spillRegister, providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase, config.narrowOopShift, config.logMinObjAlignment);
+            } else {
+                asm.movq(spillRegister, nMethodAddress);
+            }
+            Label doProlog = new Label();
+
+            asm.cmpq(spillRegister, 0);
+            asm.jcc(ConditionFlag.Equal, doProlog);
+
+            AMD64Address codeBlobAddress = new AMD64Address(spillRegister, OptimizedCallTargetFieldInfo.getCodeBlobFieldOffset());
+            asm.movq(spillRegister, codeBlobAddress);
+            asm.cmpq(spillRegister, 0);
+            asm.jcc(ConditionFlag.Equal, doProlog);
+
+            AMD64Address verifiedEntryPointAddress = new AMD64Address(spillRegister, config.nmethodEntryOffset);
+            asm.movq(spillRegister, verifiedEntryPointAddress);
+
+            asm.jmp(spillRegister);
+
+            asm.bind(doProlog);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java	Tue Oct 22 13:25:37 2013 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013, 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.hotspot.amd64.util;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.truffle.*;
+
+public class OptimizedCallTargetFieldInfo {
+
+    private static final Unsafe unsafe = UnsafeAccess.unsafe;
+    private static int compiledMethodFieldOffset = -1;
+    private static int codeBlobFieldOffset = -1;
+
+    public static int getCodeBlobFieldOffset() {
+        if (codeBlobFieldOffset == -1) {
+            try {
+                HotSpotInstalledCode.class.getDeclaredField("codeBlob").setAccessible(true);
+                Field codeBlobField = HotSpotInstalledCode.class.getDeclaredField("codeBlob");
+                codeBlobFieldOffset = (int) unsafe.objectFieldOffset(codeBlobField);
+            } catch (NoSuchFieldException | SecurityException e) {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+            return codeBlobFieldOffset;
+        } else {
+            return codeBlobFieldOffset;
+        }
+    }
+
+    public static int getCompiledMethodFieldOffset() {
+        if (compiledMethodFieldOffset == -1) {
+            try {
+                OptimizedCallTarget.class.getDeclaredField("compiledMethod").setAccessible(true);
+                Field compiledMethodField = OptimizedCallTarget.class.getDeclaredField("compiledMethod");
+                compiledMethodFieldOffset = (int) unsafe.objectFieldOffset(compiledMethodField);
+            } catch (NoSuchFieldException | SecurityException e) {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+            return compiledMethodFieldOffset;
+        } else {
+            return compiledMethodFieldOffset;
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Oct 22 13:24:43 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Tue Oct 22 13:25:37 2013 +0200
@@ -22,11 +22,28 @@
  */
 package com.oracle.graal.truffle;
 
+import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.truffle.TruffleCompilerOptions.*;
 
+import java.lang.reflect.*;
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+import com.oracle.graal.runtime.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.impl.*;
@@ -45,8 +62,17 @@
     private Replacements truffleReplacements;
     private ArrayList<String> includes;
     private ArrayList<String> excludes;
+    private final CodeCacheProvider codeCacheProvider;
+    private final ResolvedJavaMethod callMethod;
+    private final CompilationResult callCompilationResult;
 
     private GraalTruffleRuntime() {
+        Providers providers = getGraalProviders();
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        codeCacheProvider = providers.getCodeCache();
+        callMethod = metaAccess.lookupJavaMethod(getCallMethod());
+        callCompilationResult = compileMethod(callMethod, providers);
+        installOptimizedCallTargetCallMethod();
     }
 
     public String getName() {
@@ -138,4 +164,39 @@
             }
         }
     }
+
+    public void installOptimizedCallTargetCallMethod() {
+        codeCacheProvider.addDefaultMethod(callMethod, callCompilationResult);
+    }
+
+    private static Method getCallMethod() {
+        Method method;
+        try {
+            method = OptimizedCallTarget.class.getDeclaredMethod("call", new Class[]{PackedFrame.class, Arguments.class});
+        } catch (NoSuchMethodException | SecurityException e) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+        return method;
+    }
+
+    private static CompilationResult compileMethod(ResolvedJavaMethod javaMethod, Providers providers) {
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Suites suites = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites();
+        suites.getHighTier().findPhase(InliningPhase.class).remove();
+        StructuredGraph graph = new StructuredGraph(javaMethod);
+        ForeignCallsProvider foreignCalls = providers.getForeignCalls();
+        new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        PhasePlan phasePlan = new PhasePlan();
+        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
+        phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+        CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
+        Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
+        return GraalCompiler.compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog(), suites,
+                        new CompilationResult());
+    }
+
+    private static Providers getGraalProviders() {
+        RuntimeProvider runtimeProvider = Graal.getRequiredCapability(RuntimeProvider.class);
+        return runtimeProvider.getHostBackend().getProviders();
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Oct 22 13:24:43 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Oct 22 13:25:37 2013 +0200
@@ -75,6 +75,14 @@
     }
 
     private Object callHelper(PackedFrame caller, Arguments args) {
+        if (compiledMethod != null && compiledMethod.isValid()) {
+            TruffleRuntime runtime = Truffle.getRuntime();
+            if (runtime instanceof GraalTruffleRuntime) {
+                OUT.printf("[truffle] reinstall OptimizedCallTarget.call code with frame prolog shortcut.");
+                OUT.println();
+                ((GraalTruffleRuntime) runtime).installOptimizedCallTargetCallMethod();
+            }
+        }
         if (TruffleCallTargetProfiling.getValue()) {
             callCount++;
         }