# HG changeset patch # User Andreas Woess # Date 1327429048 -3600 # Node ID 3c21eee8ab4d2b8d1a490e27cf8643b08122cb2b # Parent 4c223446c28e4150abb35b0b45eb0c50e75795ea Add installMethodCallback() to HotSpotRuntime. Re-add tail call node and opcode. diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java --- 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. diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotTargetMethod.java --- 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)); } diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/VMToCompilerImpl.java --- 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); diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/nodes/TailcallNode.java --- /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 parameters = new ArrayList<>(); + for (int i = 0; i < cc.locations.length; i++) { + parameters.add(frameState.localAt(i)); + } + List 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)); + } +} diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- 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; } } diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java --- 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; + } } diff -r 4c223446c28e -r 3c21eee8ab4d graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOpcode.java --- /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 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(); + } + } +} diff -r 4c223446c28e -r 3c21eee8ab4d src/share/vm/compiler/compileBroker.cpp --- 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); diff -r 4c223446c28e -r 3c21eee8ab4d src/share/vm/graal/graalCodeInstaller.cpp --- 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(); } diff -r 4c223446c28e -r 3c21eee8ab4d src/share/vm/graal/graalJavaAccess.hpp --- 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;") \ diff -r 4c223446c28e -r 3c21eee8ab4d src/share/vm/memory/heap.cpp --- 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"); diff -r 4c223446c28e -r 3c21eee8ab4d src/share/vm/runtime/java.cpp --- 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.