# HG changeset patch # User Doug Simon # Date 1334785147 -7200 # Node ID 467de393651a57edbd9a23abfa8f4a63516120bf # Parent 0f6f647e8a9608c5a13efe6c6517ae082645e5ae optimization: frame prologue & epilogue ommitted for methods with no spills, no callee-saved registers, no incoming stack args and no debug info diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Apr 18 23:39:07 2012 +0200 @@ -276,8 +276,7 @@ targetMethod.setAssumptions(assumptions); } - Debug.dump(lir, "After code generation"); - Debug.dump(targetMethod, "Generated code"); + Debug.dump(targetMethod, "After code generation"); return targetMethod; } } diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Apr 18 23:39:07 2012 +0200 @@ -490,7 +490,14 @@ CiValue[] params = new CiValue[incomingArguments.locations.length]; for (int i = 0; i < params.length; i++) { params[i] = toStackKind(incomingArguments.locations[i]); + if (CiValueUtil.isStackSlot(params[i])) { + CiStackSlot slot = CiValueUtil.asStackSlot(params[i]); + if (slot.inCallerFrame() && !lir.hasArgInCallerFrame()) { + lir.setHasArgInCallerFrame(); + } + } } + append(new ParametersOp(params)); for (LocalNode local : graph.getNodes(LocalNode.class)) { diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Wed Apr 18 23:39:07 2012 +0200 @@ -80,13 +80,13 @@ /** * Emits code to do stack overflow checking. - * + * * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate the current frame */ - protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, LIR lir, boolean afterFrameInit) { + protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, boolean afterFrameInit) { if (GraalOptions.StackShadowPages > 0) { int frameSize = tasm.frameMap.frameSize(); - if (frameSize > 0 || lir.containsCalls()) { + if (frameSize > 0) { int lastFramePage = frameSize / tasm.target.pageSize; // emit multiple stack bangs for methods with frames larger than a page for (int i = 0; i <= lastFramePage; i++) { diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Wed Apr 18 23:39:07 2012 +0200 @@ -158,6 +158,10 @@ } } + /** + * Searches the current debug scope, bottom up, for a context object that is an instance of a given type. + * The first such object found is returned. + */ @SuppressWarnings("unchecked") public static T contextLookup(Class clazz) { if (ENABLED) { diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java Wed Apr 18 23:39:07 2012 +0200 @@ -42,11 +42,11 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.java.*; import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ci.CiCallingConvention.Type; -import com.oracle.max.cri.ci.CiRegister.*; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; @@ -89,45 +89,32 @@ class HotSpotFrameContext implements FrameContext { - private final LIR lir; - private boolean needsLeave; - - public HotSpotFrameContext(LIR lir) { - this.lir = lir; - } - @Override public void enter(TargetMethodAssembler tasm) { FrameMap frameMap = tasm.frameMap; int frameSize = frameMap.frameSize(); - if (frameSize != 0) { - AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; - emitStackOverflowCheck(tasm, lir, false); - asm.push(rbp); - asm.movq(rbp, rsp); - asm.decrementq(rsp, frameSize - 8); // account for the push of RBP above - if (GraalOptions.ZapStackOnMethodEntry) { - final int intSize = 4; - for (int i = 0; i < frameSize / intSize; ++i) { - asm.movl(new CiAddress(CiKind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1); - } + + AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; + emitStackOverflowCheck(tasm, false); + asm.push(rbp); + asm.movq(rbp, rsp); + asm.decrementq(rsp, frameSize - 8); // account for the push of RBP above + if (GraalOptions.ZapStackOnMethodEntry) { + final int intSize = 4; + for (int i = 0; i < frameSize / intSize; ++i) { + asm.movl(new CiAddress(CiKind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1); } - CiCalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout(); - if (csl != null && csl.size != 0) { - int frameToCSA = frameMap.offsetToCalleeSaveArea(); - assert frameToCSA >= 0; - asm.save(csl, frameToCSA); - } - needsLeave = true; + } + CiCalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout(); + if (csl != null && csl.size != 0) { + int frameToCSA = frameMap.offsetToCalleeSaveArea(); + assert frameToCSA >= 0; + asm.save(csl, frameToCSA); } } @Override public void leave(TargetMethodAssembler tasm) { - if (!needsLeave) { - return; - } - int frameSize = tasm.frameMap.frameSize(); AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm; CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout(); @@ -165,8 +152,19 @@ @Override public TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir) { + // Omit the frame if the method: + // - has no spill slots or other slots allocated during register allocation + // - has no callee-saved registers + // - has no incoming arguments passed on the stack + // - has no instructions with debug info + boolean canOmitFrame = + frameMap.frameSize() == frameMap.initialFrameSize && + frameMap.registerConfig.getCalleeSaveLayout().registers.length == 0 && + !lir.hasArgInCallerFrame() && + !lir.hasDebugInfo(); + AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig); - HotSpotFrameContext frameContext = new HotSpotFrameContext(lir); + HotSpotFrameContext frameContext = canOmitFrame ? null : new HotSpotFrameContext(); TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime, frameMap, masm, frameContext); tasm.setFrameSize(frameMap.frameSize()); tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea()); @@ -202,28 +200,34 @@ // Emit code for the LIR lir.emitCode(tasm); - // Emit the suffix (i.e. out-of-line stubs) - CiRegister thread = r15; - CiRegister exceptionOop = regConfig.getCallingConventionRegisters(Type.RuntimeCall, RegisterFlag.CPU)[0]; - Label unwind = new Label(); - asm.bind(unwind); - tasm.recordMark(MARK_UNWIND_ENTRY); - CiAddress exceptionOopField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionOopOffset); - CiAddress exceptionPcField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionPcOffset); - asm.movq(exceptionOop, exceptionOopField); - asm.movslq(exceptionOopField, 0); - asm.movslq(exceptionPcField, 0); + boolean frameOmitted = tasm.frameContext == null; + if (!frameOmitted) { + CiRegister thread = r15; + CiRegister exceptionOop = regConfig.getCallingConventionRegisters(Type.RuntimeCall, RegisterFlag.CPU)[0]; + Label unwind = new Label(); + asm.bind(unwind); + tasm.recordMark(MARK_UNWIND_ENTRY); + CiAddress exceptionOopField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionOopOffset); + CiAddress exceptionPcField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionPcOffset); + asm.movq(exceptionOop, exceptionOopField); + asm.movslq(exceptionOopField, 0); + asm.movslq(exceptionPcField, 0); - AMD64Call.directCall(tasm, asm, config.unwindExceptionStub, null); - AMD64Call.shouldNotReachHere(tasm, asm); + AMD64Call.directCall(tasm, asm, config.unwindExceptionStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); + + tasm.recordMark(MARK_EXCEPTION_HANDLER_ENTRY); + AMD64Call.directCall(tasm, asm, config.handleExceptionStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); - tasm.recordMark(MARK_EXCEPTION_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, config.handleExceptionStub, null); - AMD64Call.shouldNotReachHere(tasm, asm); - - tasm.recordMark(MARK_DEOPT_HANDLER_ENTRY); - AMD64Call.directCall(tasm, asm, config.handleDeoptStub, null); - AMD64Call.shouldNotReachHere(tasm, asm); + tasm.recordMark(MARK_DEOPT_HANDLER_ENTRY); + AMD64Call.directCall(tasm, asm, config.handleDeoptStub, null); + AMD64Call.shouldNotReachHere(tasm, asm); + } else { + // No need to emit the stubs for entries back into the method since + // it has no calls that can cause such "return" entries + assert !frameMap.accessesCallerFrame(); + } if (!isStatic) { asm.bind(unverifiedStub); diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Wed Apr 18 23:39:07 2012 +0200 @@ -46,7 +46,9 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - tasm.frameContext.leave(tasm); + if (tasm.frameContext != null) { + tasm.frameContext.leave(tasm); + } masm.ret(0); } diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java Wed Apr 18 23:39:07 2012 +0200 @@ -85,6 +85,12 @@ public final RiRegisterConfig registerConfig; /** + * The initial frame size, not including the size of the return address. + * This is the constant space reserved by the runtime for all compiled methods. + */ + public final int initialFrameSize; + + /** * The final frame size, not including the size of the return address. * The value is only set after register allocation is complete, i.e., after all spill slots have been allocated. */ @@ -112,6 +118,11 @@ private final CiStackSlot customArea; /** + * Records whether an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}. + */ + private boolean accessesCallerFrame; + + /** * Creates a new frame map for the specified method. */ public FrameMap(RiRuntime runtime, CiTarget target, RiRegisterConfig registerConfig) { @@ -123,9 +134,9 @@ this.outgoingSize = runtime.getMinimumOutgoingSize(); this.objectStackBlocks = new ArrayList<>(); this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false); + this.initialFrameSize = currentFrameSize(); } - private int returnAddressSize() { return target.arch.returnAddressSize; } @@ -136,6 +147,13 @@ } /** + * Determines if an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}. + */ + public boolean accessesCallerFrame() { + return accessesCallerFrame; + } + + /** * Gets the frame size of the compiled frame, not including the size of the return address. * @return The size of the frame (in bytes). */ @@ -153,20 +171,20 @@ } /** - * Sets the frame size for this frame. - * @param frameSize The frame size (in bytes). + * Gets the current size of this frame. This is the size that would be returned by + * {@link #frameSize()} if {@link #finish()} were called now. */ - public void setFrameSize(int frameSize) { - assert this.frameSize == -1 : "must only be set once"; - this.frameSize = frameSize; + public int currentFrameSize() { + return target.alignFrameSize(outgoingSize + spillSize - returnAddressSize()); } /** - * Computes the frame size for this frame. After this method has been called, methods that change the + * Computes the final size of this frame. After this method has been called, methods that change the * frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can be requested. */ public void finish() { - setFrameSize(target.alignFrameSize(outgoingSize + spillSize - returnAddressSize())); + assert this.frameSize == -1 : "must only be set once"; + frameSize = currentFrameSize(); } /** @@ -180,6 +198,9 @@ assert (!slot.rawAddFrameSize() && slot.rawOffset() < outgoingSize) || (slot.rawAddFrameSize() && slot.rawOffset() < 0 && -slot.rawOffset() <= spillSize) || (slot.rawAddFrameSize() && slot.rawOffset() >= 0); + if (slot.inCallerFrame()) { + accessesCallerFrame = true; + } return slot.offset(totalFrameSize()); } diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Wed Apr 18 23:39:07 2012 +0200 @@ -54,7 +54,6 @@ */ private final List codeEmittingOrder; - public final List slowPaths; public final List deoptimizationStubs; @@ -68,6 +67,8 @@ LIRInstruction createExchange(CiValue input1, CiValue input2); } + private boolean hasArgInCallerFrame; + /** * An opaque chunk of machine code. */ @@ -98,15 +99,12 @@ } /** - * Determines if this LIR contains any calls. + * Determines if any instruction in the LIR has any debug info associated with it. */ - public boolean containsCalls() { - if (!slowPaths.isEmpty() || !deoptimizationStubs.isEmpty()) { - return true; - } - for (Block b : linearScanOrder) { + public boolean hasDebugInfo() { + for (Block b : linearScanOrder()) { for (LIRInstruction op : b.lir) { - if (op.hasCall()) { + if (op.info != null) { return true; } } @@ -135,7 +133,9 @@ } public void emitCode(TargetMethodAssembler tasm) { - tasm.frameContext.enter(tasm); + if (tasm.frameContext != null) { + tasm.frameContext.enter(tasm); + } for (Block b : codeEmittingOrder()) { emitBlock(tasm, b); @@ -189,6 +189,18 @@ sp.emitCode(tasm); } + public void setHasArgInCallerFrame() { + hasArgInCallerFrame = true; + } + + /** + * Determines if any of the parameters to the method are passed via the stack + * where the parameters are located in the caller's frame. + */ + public boolean hasArgInCallerFrame() { + return hasArgInCallerFrame; + } + /* private int lastDecodeStart; diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java Wed Apr 18 23:39:07 2012 +0200 @@ -24,8 +24,7 @@ /** - * Emits common code for {@linkplain #enter(TargetMethodAssembler) entering} and - * {@linkplain #leave(TargetMethodAssembler) leaving} a method. + * Code for managing a method's native frame. */ public interface FrameContext { /** diff -r 0f6f647e8a96 -r 467de393651a graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Wed Apr 18 23:19:58 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java Wed Apr 18 23:39:07 2012 +0200 @@ -52,6 +52,11 @@ public final RiRuntime runtime; public final FrameMap frameMap; public final List slowPaths; + + /** + * The object that emits code for managing a method's frame. + * If null, no frame is used by the method. + */ public final FrameContext frameContext; private List exceptionInfoList; diff -r 0f6f647e8a96 -r 467de393651a src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Apr 18 23:19:58 2012 +0200 +++ b/src/share/vm/code/nmethod.cpp Wed Apr 18 23:39:07 2012 +0200 @@ -833,19 +833,28 @@ _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); - // Exception handler and deopt handler are in the stub section - assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); - assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); #ifdef GRAAL // graal produces no (!) stub section - _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); - _deoptimize_offset = code_offset() + offsets->value(CodeOffsets::Deopt); + if (offsets->value(CodeOffsets::Exceptions) != -1) { + _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); + } else { + _exception_offset = -1; + } + if (offsets->value(CodeOffsets::Deopt) != -1) { + _deoptimize_offset = code_offset() + offsets->value(CodeOffsets::Deopt); + } else { + _deoptimize_offset = -1; + } if (offsets->value(CodeOffsets::DeoptMH) != -1) { _deoptimize_mh_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); } else { _deoptimize_mh_offset = -1; } #else + // Exception handler and deopt handler are in the stub section + assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); + assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); if (offsets->value(CodeOffsets::DeoptMH) != -1) { diff -r 0f6f647e8a96 -r 467de393651a src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Wed Apr 18 23:19:58 2012 +0200 +++ b/src/share/vm/code/nmethod.hpp Wed Apr 18 23:39:07 2012 +0200 @@ -340,6 +340,9 @@ bool is_compiled_by_c2() const; bool is_compiled_by_shark() const; + +#define CHECK_POSITIVE(val) assert(val, "should be positive") + // boundaries for different parts address consts_begin () const { return header_begin() + _consts_offset ; } address consts_end () const { return header_begin() + code_offset() ; } @@ -347,8 +350,8 @@ address insts_end () const { return header_begin() + _stub_offset ; } address stub_begin () const { return header_begin() + _stub_offset ; } address stub_end () const { return header_begin() + _oops_offset ; } - address exception_begin () const { return header_begin() + _exception_offset ; } - address deopt_handler_begin () const { return header_begin() + _deoptimize_offset ; } + address exception_begin () const { assert(_exception_offset >= 0, "no exception handler"); return header_begin() + _exception_offset ; } + address deopt_handler_begin () const { assert(_deoptimize_offset >= 0, "no deopt handler"); return header_begin() + _deoptimize_offset ; } address deopt_mh_handler_begin() const { return header_begin() + _deoptimize_mh_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; } oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } diff -r 0f6f647e8a96 -r 467de393651a src/share/vm/graal/graalEnv.cpp --- a/src/share/vm/graal/graalEnv.cpp Wed Apr 18 23:19:58 2012 +0200 +++ b/src/share/vm/graal/graalEnv.cpp Wed Apr 18 23:39:07 2012 +0200 @@ -477,9 +477,6 @@ return NULL; } - assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry"); - assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry"); - nm = nmethod::new_nmethod(method, compile_id, entry_bci, @@ -531,13 +528,13 @@ old->make_not_entrant(); } } - if (TraceNMethodInstalls ) { + if (TraceNMethodInstalls) { ResourceMark rm; char *method_name = method->name_and_sig_as_C_string(); ttyLocker ttyl; - tty->print_cr("Installing method (%d) %s ", + tty->print_cr("Installing method (%d) %s [entry point: %p]", comp_level, - method_name); + method_name, nm->entry_point()); } // Allow the code to be executed method->set_code(method, nm);