changeset 4319:3c21eee8ab4d

Add installMethodCallback() to HotSpotRuntime. Re-add tail call node and opcode.
author Andreas Woess <andreas.woess@jku.at>
date Tue, 24 Jan 2012 19:17:28 +0100
parents 4c223446c28e
children 125678ef7587
files graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotTargetMethod.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/nodes/TailcallNode.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOpcode.java src/share/vm/compiler/compileBroker.cpp src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalJavaAccess.hpp src/share/vm/memory/heap.cpp src/share/vm/runtime/java.cpp
diffstat 12 files changed, 255 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java	Mon Jan 23 12:21:06 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java	Tue Jan 24 19:17:28 2012 +0100
@@ -186,7 +186,7 @@
      * @param method a method whose executable code is being modified
      * @param code the code to be executed when {@code method} is called
      */
-    void installMethod(RiMethod method, CiTargetMethod code);
+    void installMethod(RiResolvedMethod method, CiTargetMethod code);
 
     /**
      * Adds the given machine code as an implementation of the given method without making it the default implementation.
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotTargetMethod.java	Mon Jan 23 12:21:06 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotTargetMethod.java	Tue Jan 24 19:17:28 2012 +0100
@@ -35,7 +35,7 @@
 public final class HotSpotTargetMethod extends CompilerObject {
 
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = 7807321392203253218L;
     public final CiTargetMethod targetMethod;
@@ -45,7 +45,7 @@
     public final Site[] sites;
     public final ExceptionHandler[] exceptionHandlers;
 
-    private HotSpotTargetMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) {
+    public HotSpotTargetMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod) {
         super(compiler);
         this.method = method;
         this.targetMethod = targetMethod;
@@ -100,10 +100,6 @@
         return result;
     }
 
-    public static HotSpotCompiledMethod installMethod(Compiler compiler, HotSpotMethodResolved method, CiTargetMethod targetMethod, boolean installCode) {
-        return compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, method, targetMethod), installCode);
-    }
-
     public static Object installStub(Compiler compiler, CiTargetMethod targetMethod, String name) {
         return compiler.getVMEntries().installStub(new HotSpotTargetMethod(compiler, targetMethod, name));
     }
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Jan 23 12:21:06 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Jan 24 19:17:28 2012 +0100
@@ -32,7 +32,6 @@
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.phases.*;
 import com.oracle.max.graal.compiler.phases.PhasePlan.PhasePosition;
-import com.oracle.max.graal.hotspot.*;
 import com.oracle.max.graal.hotspot.Compiler;
 import com.oracle.max.graal.hotspot.ri.*;
 import com.oracle.max.graal.hotspot.server.*;
@@ -182,7 +181,7 @@
                         GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(compiler.getRuntime());
                         plan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
                         CiTargetMethod result = compiler.getCompiler().compileMethod(method, -1, plan);
-                        HotSpotTargetMethod.installMethod(compiler, method, result, true);
+                        compiler.getRuntime().installMethod(method, result);
                     } catch (CiBailout bailout) {
                         if (GraalOptions.ExitVMOnBailout) {
                             bailout.printStackTrace(TTY.cachedOut);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/nodes/TailcallNode.java	Tue Jan 24 19:17:28 2012 +0100
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011, 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.max.graal.hotspot.nodes;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.hotspot.*;
+import com.oracle.max.graal.hotspot.target.amd64.*;
+import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.spi.*;
+import com.oracle.max.graal.nodes.type.*;
+
+/**
+ * Performs a tail call to the specified target compiled method, with the parameter taken from the supplied FrameState.
+ */
+public class TailcallNode extends FixedWithNextNode implements LIRLowerable {
+
+    @Input private final FrameState frameState;
+    @Input private final ValueNode target;
+
+    /**
+     * Creates a TailcallNode.
+     * @param target points to the start of an nmethod
+     * @param frameState the parameters will be taken from this FrameState
+     */
+    public TailcallNode(ValueNode target, FrameState frameState) {
+        super(StampFactory.illegal());
+        this.target = target;
+        this.frameState = frameState;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        LIRGenerator gen = (LIRGenerator) generator;
+        HotSpotVMConfig config = CompilerImpl.getInstance().getConfig();
+        RiResolvedMethod method = frameState.method();
+        boolean isStatic = Modifier.isStatic(method.accessFlags());
+
+        CiKind[] signature = CiUtil.signatureToKinds(method.signature(), isStatic ? null : method.holder().kind(true));
+        CiCallingConvention cc = gen.frameMap().registerConfig.getCallingConvention(CiCallingConvention.Type.JavaCall, signature, gen.target(), false);
+        gen.frameMap().callsMethod(cc, CiCallingConvention.Type.JavaCall);
+        List<ValueNode> parameters = new ArrayList<>();
+        for (int i = 0; i < cc.locations.length; i++) {
+            parameters.add(frameState.localAt(i));
+        }
+        List<CiValue> argList = gen.visitInvokeArguments(cc, parameters, null);
+
+        CiValue entry = gen.emitLoad(new CiAddress(CiKind.Long, gen.operand(target), config.nmethodEntryOffset), false);
+
+        gen.append(AMD64TailcallOpcode.TAILCALL.create(argList, entry, cc.locations));
+    }
+}
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Mon Jan 23 12:21:06 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Tue Jan 24 19:17:28 2012 +0100
@@ -57,6 +57,7 @@
     private RiResolvedType holder;
     private byte[] code;
     private boolean canBeInlined;
+    private CiGenericCallback callback;
 
     private HotSpotMethodResolvedImpl() {
         super(null);
@@ -306,10 +307,16 @@
 
     @Override
     public boolean canBeInlined() {
-        return canBeInlined;
+        return canBeInlined && callback == null;
+    }
+    public void neverInline() {
+        this.canBeInlined = false;
     }
 
-    public void setCanBeInlined(boolean canBeInlined) {
-        this.canBeInlined = canBeInlined;
+    public CiGenericCallback callback() {
+        return callback;
+    }
+    public void setCallback(CiGenericCallback callback) {
+        this.callback = callback;
     }
 }
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Mon Jan 23 12:21:06 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Tue Jan 24 19:17:28 2012 +0100
@@ -34,12 +34,15 @@
 import com.oracle.max.cri.ri.RiType.Representation;
 import com.oracle.max.criutils.*;
 import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.phases.*;
 import com.oracle.max.graal.cri.*;
 import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.hotspot.*;
 import com.oracle.max.graal.hotspot.Compiler;
 import com.oracle.max.graal.hotspot.nodes.*;
+import com.oracle.max.graal.java.*;
 import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction;
 import com.oracle.max.graal.nodes.calc.*;
 import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.java.*;
@@ -399,18 +402,82 @@
         return (RiResolvedMethod) compiler.getVMEntries().getRiMethod(reflectionMethod);
     }
 
-    public void installMethod(RiMethod method, CiTargetMethod code) {
-        HotSpotTargetMethod.installMethod(CompilerImpl.getInstance(), (HotSpotMethodResolved) method, code, true);
+    @Override
+    public void installMethod(RiResolvedMethod method, CiTargetMethod code) {
+        synchronized (method) {
+            if (((HotSpotMethodResolvedImpl) method).callback() == null) {
+                compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), true);
+            } else {
+                // callback stub is installed.
+            }
+        }
     }
 
     @Override
     public RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code) {
-        Compiler compilerInstance = CompilerImpl.getInstance();
-        return HotSpotTargetMethod.installMethod(compilerInstance, (HotSpotMethodResolved) method, code, false);
+        return compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), false);
+    }
+
+    public void installMethodCallback(RiResolvedMethod method, CiGenericCallback callback) {
+        synchronized (method) {
+            ((HotSpotMethodResolvedImpl) method).setCallback(callback);
+            CiTargetMethod callbackStub = createCallbackStub(method, callback);
+            compiler.getVMEntries().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, callbackStub), true);
+        }
     }
 
     @Override
     public RiRegisterConfig getGlobalStubRegisterConfig() {
         return globalStubRegConfig;
     }
+
+    private CiTargetMethod createCallbackStub(RiResolvedMethod method, CiGenericCallback callback) {
+        StructuredGraph graph = new StructuredGraph();
+        FrameStateBuilder frameState = new FrameStateBuilder(method, method.maxLocals(), method.maxStackSize(), graph);
+        ValueNode local0 = frameState.loadLocal(0);
+
+        FrameState initialFrameState = frameState.create(0);
+        graph.start().setStateAfter(initialFrameState);
+
+        ConstantNode callbackNode = ConstantNode.forObject(callback, this, graph);
+
+        RuntimeCallNode runtimeCall = graph.add(new RuntimeCallNode(CiRuntimeCall.GenericCallback, new ValueNode[] {callbackNode, local0}));
+        runtimeCall.setStateAfter(initialFrameState.duplicateModified(0, false, CiKind.Void, runtimeCall));
+
+        @SuppressWarnings("unused")
+        HotSpotCompiledMethod hotSpotCompiledMethod = new HotSpotCompiledMethod(null); // initialize class...
+        RiResolvedType compiledMethodClass = getType(HotSpotCompiledMethod.class);
+        RiResolvedField nmethodField = null;
+        for (RiResolvedField field : compiledMethodClass.declaredFields()) {
+            if (field.name().equals("nmethod")) {
+                nmethodField = field;
+                break;
+            }
+        }
+        assert nmethodField != null;
+        LoadFieldNode loadField = graph.add(new LoadFieldNode(runtimeCall, nmethodField));
+
+        CompareNode compare = graph.unique(new CompareNode(loadField, Condition.EQ, ConstantNode.forLong(0, graph)));
+
+        IfNode ifNull = graph.add(new IfNode(compare, 0.01));
+
+        BeginNode beginInvalidated = graph.add(new BeginNode());
+        DeoptimizeNode deoptInvalidated = graph.add(new DeoptimizeNode(DeoptAction.None));
+
+        BeginNode beginTailcall = graph.add(new BeginNode());
+        TailcallNode tailcall = graph.add(new TailcallNode(loadField, initialFrameState));
+        DeoptimizeNode deoptEnd = graph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile));
+
+        graph.start().setNext(runtimeCall);
+        runtimeCall.setNext(loadField);
+        loadField.setNext(ifNull);
+        ifNull.setTrueSuccessor(beginInvalidated);
+        ifNull.setFalseSuccessor(beginTailcall);
+        beginInvalidated.setNext(deoptInvalidated);
+        beginTailcall.setNext(tailcall);
+        tailcall.setNext(deoptEnd);
+
+        CiTargetMethod result = compiler.getCompiler().compileMethod(method, graph, -1, PhasePlan.DEFAULT);
+        return result;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOpcode.java	Tue Jan 24 19:17:28 2012 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2011, 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.max.graal.hotspot.target.amd64;
+
+import static com.oracle.max.cri.ci.CiValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.graal.compiler.asm.*;
+import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.compiler.target.amd64.*;
+import com.oracle.max.graal.compiler.util.*;
+
+/**
+ * Performs a hard-coded tail call to the specified target, which normally should be an RiCompiledCode instance.
+ */
+public enum AMD64TailcallOpcode implements LIROpcode {
+    TAILCALL;
+
+    public LIRInstruction create(List<CiValue> parameters, CiValue target, CiValue[] callingConvention) {
+        CiValue[] inputs = new CiValue[parameters.size() + 1];
+        parameters.toArray(inputs);
+        inputs[parameters.size()] = target;
+        CiValue[] temps = callingConvention.clone();
+        assert inputs.length == temps.length + 1;
+
+        return new AMD64LIRInstruction(this, LIRInstruction.NO_OPERANDS, null, inputs, LIRInstruction.NO_OPERANDS, temps) {
+            @Override
+            public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+                emit(tasm, masm, inputs, temps);
+            }
+        };
+    }
+
+    private void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue[] inputs, CiValue[] temps) {
+        switch (this) {
+            case TAILCALL: {
+                // move all parameters to the correct positions, according to the calling convention
+                // TODO: These moves should not be part of the TAILCALL opcode, but emitted as separate MOVE instructions before.
+                for (int i = 0; i < inputs.length - 1; i++) {
+                    assert inputs[i].kind == CiKind.Object || inputs[i].kind == CiKind.Int || inputs[i].kind == CiKind.Long : "only Object, int and long supported for now";
+                    assert isRegister(temps[i]) : "too many parameters";
+                    if (isRegister(inputs[i])) {
+                        if (inputs[i] != temps[i]) {
+                            masm.movq(asRegister(temps[i]), asRegister(inputs[i]));
+                        }
+                    } else {
+                        masm.movq(asRegister(temps[i]), tasm.asAddress(inputs[i]));
+                    }
+                }
+                // destroy the current frame (now the return address is the top of stack)
+                masm.leave();
+
+                // jump to the target method
+                masm.jmp(asRegister(inputs[inputs.length - 1]));
+                masm.ensureUniquePC();
+                break;
+            }
+            default:   throw Util.shouldNotReachHere();
+        }
+    }
+}
--- a/src/share/vm/compiler/compileBroker.cpp	Mon Jan 23 12:21:06 2012 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Tue Jan 24 19:17:28 2012 +0100
@@ -1120,12 +1120,14 @@
                                blocking);*/
   }
 
+#ifdef GRAAL
   if (!JavaThread::current()->is_compiling()) {
     method->set_queued_for_compilation();
     GraalCompiler::instance()->compile_method(method, osr_bci, blocking);
   } else {
     // Recursive compile request => ignore.
   }
+#endif
 
   /*if (blocking) {
     wait_for_completion(task);
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon Jan 23 12:21:06 2012 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Tue Jan 24 19:17:28 2012 +0100
@@ -275,10 +275,10 @@
 
   int stack_slots = _total_frame_size / HeapWordSize; // conversion to words
   methodHandle method = getMethodFromHotSpotMethod(HotSpotTargetMethod::method(JNIHandles::resolve(target_method_obj))); 
-  {
-    nm = GraalEnv::register_method(method, -1, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-      &_implicit_exception_table, GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, true, false, install_code);
-  }
+
+  nm = GraalEnv::register_method(method, -1, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
+    &_implicit_exception_table, GraalCompiler::instance(), _debug_recorder, _dependencies, NULL, -1, true, false, install_code);
+
   method->clear_queued_for_compilation();
 }
 
--- a/src/share/vm/graal/graalJavaAccess.hpp	Mon Jan 23 12:21:06 2012 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Tue Jan 24 19:17:28 2012 +0100
@@ -68,6 +68,7 @@
     int_field(HotSpotMethodResolved, maxLocals)                                         \
     int_field(HotSpotMethodResolved, maxStackSize)                                      \
     boolean_field(HotSpotMethodResolved, canBeInlined)                                  \
+    oop_field(HotSpotMethodResolved, callback, "Lcom/oracle/max/cri/ci/CiGenericCallback;") \
   end_class                                                                             \
   start_class(HotSpotType)                                                              \
     oop_field(HotSpotType, name, "Ljava/lang/String;")                                  \
--- a/src/share/vm/memory/heap.cpp	Mon Jan 23 12:21:06 2012 +0100
+++ b/src/share/vm/memory/heap.cpp	Tue Jan 24 19:17:28 2012 +0100
@@ -127,7 +127,7 @@
   assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking");
 
   // reserve space for _segmap
-  if (!_segmap.initialize(align_to_page_size(_number_of_reserved_segments), align_to_page_size(_number_of_committed_segments))) {
+  if (!_segmap.initialize(align_to_allocation_size(_number_of_reserved_segments), align_to_allocation_size(_number_of_committed_segments))) {
     return false;
   }
   assert(_segmap.committed_size() >= (size_t) _number_of_committed_segments, "could not commit  enough space for segment map");
--- a/src/share/vm/runtime/java.cpp	Mon Jan 23 12:21:06 2012 +0100
+++ b/src/share/vm/runtime/java.cpp	Tue Jan 24 19:17:28 2012 +0100
@@ -425,9 +425,11 @@
   #define BEFORE_EXIT_DONE    2
   static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;
 
+#ifdef GRAAL
   if (UseGraal) {
     GraalCompiler::instance()->exit();
   }
+#endif
 
   // Note: don't use a Mutex to guard the entire before_exit(), as
   // JVMTI post_thread_end_event and post_vm_death_event will run native code.