/* * 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.sun.max.vm.compiler.target; import static com.sun.max.platform.Platform.*; import static com.sun.max.vm.MaxineVM.*; import static com.sun.max.vm.compiler.target.Safepoints.*; import static com.sun.max.vm.compiler.target.Stub.Type.*; import java.util.*; import com.sun.cri.bytecode.*; import com.sun.cri.ci.*; import com.sun.max.annotate.*; import com.sun.max.lang.*; import com.sun.max.unsafe.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.code.*; import com.sun.max.vm.code.CodeManager.Lifespan; import com.sun.max.vm.compiler.*; import com.sun.max.vm.compiler.target.amd64.*; import com.sun.max.vm.runtime.*; import com.sun.max.vm.stack.*; /** * Stubs are for manually-assembled target code. Currently, a stub has the maximum of one * direct call to another method, so the callee is passed into the constructor directly. * Stack walking of stub frames is done with the same code as for optimized compiler frames. */ public final class Stub extends TargetMethod { public enum Type { /** * Trampoline for virtual method dispatch (i.e. translation of {@link Bytecodes#INVOKEVIRTUAL}). */ VirtualTrampoline, /** * Trampoline for interface method dispatch (i.e. translation of {@link Bytecodes#INVOKEINTERFACE}). */ InterfaceTrampoline, /** * Trampoline for static method call (i.e. translation of {@link Bytecodes#INVOKESPECIAL} or {@link Bytecodes#INVOKESTATIC}). */ StaticTrampoline, /** * A stub that performs an operation on behalf of compiled code. * These stubs are called with a callee-save convention; the stub must save any * registers it may destroy and then restore them upon return. This allows the register * allocator to ignore calls to such stubs. Parameters to compiler stubs are * passed on the stack in order to preserve registers for the rest of the code. */ CompilerStub, UnwindStub, UnrollStub, UncommonTrapStub, /** * Transition when returning from a normal call to a method being deoptimized. */ DeoptStub, /** * Transition when returning from a compiler stub to a method being deoptimized. This * stub creates an intermediate frame to (re)save all the registers saved by a compiler stub. * * @see #CompilerStub */ DeoptStubFromCompilerStub, /** * Transition when returning from a trap stub to a method being deoptimized. This * stub creates an intermediate frame to (re)save all the registers saved by the trap stub. * * @see Stubs#genTrapStub() */ DeoptStubFromSafepoint, /** * The trap stub. */ TrapStub, /** * A place holder for invalid indexes of dispatch tables (virtual / interface). */ InvalidIndexTrampoline } @HOSTED_ONLY private static final Stub canonicalInvalidIndexStub = new Stub(); @HOSTED_ONLY public static Stub canonicalInvalidIndexStub() { return canonicalInvalidIndexStub; } /** * Determines if a given address in a given target method denotes the entry point of a deoptimization stub. * * @param ip a code address * @param tm the target method {@linkplain Code#codePointerToTargetMethod(Pointer) found} in the code cache based on {@code ip} */ public static boolean isDeoptStubEntry(Pointer ip, TargetMethod tm) { if (tm != null && (tm.is(DeoptStub) || tm.is(DeoptStubFromCompilerStub) || tm.is(DeoptStubFromSafepoint))) { return ip.asPointer().equals(tm.codeStart()); } else { return false; } } public final Type type; @Override public Stub.Type stubType() { return type; } @HOSTED_ONLY private Stub() { super("Invalid Index stub", CallEntryPoint.OPTIMIZED_ENTRY_POINT); type = InvalidIndexTrampoline; } public Stub(Type type, String stubName, int frameSize, byte[] code, int callPos, int callSize, ClassMethodActor callee, int registerRestoreEpilogueOffset) { super(stubName, CallEntryPoint.OPTIMIZED_ENTRY_POINT); this.type = type; this.setFrameSize(frameSize); this.setRegisterRestoreEpilogueOffset(registerRestoreEpilogueOffset); final TargetBundleLayout targetBundleLayout = new TargetBundleLayout(0, 0, code.length); Code.allocate(targetBundleLayout, this); setData(null, null, code); if (callPos != -1) { int safepointPos = Safepoints.safepointPosForCall(callPos, callSize); assert callee != null; setSafepoints(new Safepoints(Safepoints.make(safepointPos, callPos, DIRECT_CALL)), new Object[] {callee}); } if (!isHosted()) { linkDirectCalls(); } } public Stub(Type type, String name, CiTargetMethod tm) { super(name, CallEntryPoint.OPTIMIZED_ENTRY_POINT); this.type = type; initCodeBuffer(tm, true); initFrameLayout(tm); CiDebugInfo[] debugInfos = initSafepoints(tm); for (CiDebugInfo info : debugInfos) { assert info == null; } } @Override public CiCalleeSaveLayout calleeSaveLayout() { final RegisterConfigs rc = vm().registerConfigs; switch (type) { case DeoptStubFromCompilerStub: case CompilerStub: return rc.compilerStub.csl; case VirtualTrampoline: case StaticTrampoline: case InterfaceTrampoline: return rc.trampoline.csl; case DeoptStubFromSafepoint: case TrapStub: return rc.trapStub.csl; case UncommonTrapStub: return rc.uncommonTrapStub.csl; } return null; } @Override public Lifespan lifespan() { return Lifespan.LONG; } @Override public Pointer returnAddressPointer(StackFrameCursor frame) { if (platform().isa == ISA.AMD64) { return AMD64TargetMethodUtil.returnAddressPointer(frame); } else { throw FatalError.unimplemented(); } } @Override public void advance(StackFrameCursor current) { if (platform().isa == ISA.AMD64) { CiCalleeSaveLayout csl = calleeSaveLayout(); Pointer csa = Pointer.zero(); if (csl != null) { assert csl.frameOffsetToCSA != Integer.MAX_VALUE : "stub should have fixed offset for CSA"; csa = current.sp().plus(csl.frameOffsetToCSA); } AMD64TargetMethodUtil.advance(current, csl, csa); } else { throw FatalError.unimplemented(); } } @Override @HOSTED_ONLY public boolean acceptStackFrameVisitor(StackFrameCursor current, StackFrameVisitor visitor) { if (platform().isa == ISA.AMD64) { return AMD64TargetMethodUtil.acceptStackFrameVisitor(current, visitor); } else { throw FatalError.unimplemented(); } } @Override public VMFrameLayout frameLayout() { if (platform().isa == ISA.AMD64) { return AMD64TargetMethodUtil.frameLayout(this); } else { throw FatalError.unimplemented(); } } @Override @HOSTED_ONLY public void gatherCalls(Set<MethodActor> directCalls, Set<MethodActor> virtualCalls, Set<MethodActor> interfaceCalls, Set<MethodActor> inlinedMethods) { if (directCallees != null && directCallees.length != 0) { assert directCallees.length == 1 && directCallees[0] instanceof ClassMethodActor; directCalls.add((MethodActor) directCallees[0]); } } @Override public boolean isPatchableCallSite(CodePointer callSite) { FatalError.unexpected("Stub should never be patched"); return false; } @Override public CodePointer fixupCallSite(int callOffset, CodePointer callEntryPoint) { return AMD64TargetMethodUtil.fixupCall32Site(this, callOffset, callEntryPoint); } @Override public CodePointer patchCallSite(int callOffset, CodePointer callEntryPoint) { throw FatalError.unexpected("Stub should never be patched"); } @Override public CodePointer throwAddressToCatchAddress(CodePointer throwAddress, Throwable exception) { return CodePointer.zero(); } @Override public void prepareReferenceMap(StackFrameCursor current, StackFrameCursor callee, FrameReferenceMapVisitor preparer) { } @Override public void catchException(StackFrameCursor current, StackFrameCursor callee, Throwable throwable) { // Exceptions do not occur in stubs } }