/*
* Copyright (c) 2010, 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.oracle.max.asm.target.amd64.AMD64.*;
import static com.sun.cri.ci.CiCallingConvention.Type.*;
import static com.sun.max.platform.Platform.*;
import static com.sun.max.vm.runtime.VMRegister.*;
import java.util.*;
import com.sun.cri.ci.*;
import com.sun.cri.ri.*;
import com.sun.max.annotate.*;
import com.sun.max.lang.*;
import com.sun.max.platform.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.compiler.deopt.*;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.runtime.amd64.*;
/**
* The set of register configurations applicable to compiled code in the VM.
*/
public class RegisterConfigs {
/**
* The register configuration for a normal Java method.
*/
public final CiRegisterConfig standard;
/**
* The register configuration for a method called directly from native/C code.
* This configuration preserves all native ABI specified callee saved registers.
*/
public final CiRegisterConfig n2j;
/**
* The register configuration for a trampoline.
* This configuration lists all parameter registers as callee saved.
*/
public final CiRegisterConfig trampoline;
/**
* The register configuration for compiling the templates used by a template-based baseline compiler (e.g. T1X).
*/
public final CiRegisterConfig bytecodeTemplate;
/**
* The register configuration for a {@link Stub.Type#CompilerStub compiler stub}.
*/
public final CiRegisterConfig compilerStub;
/**
* The register configuration for the {@linkplain Stubs#trapStub trap stub}.
*/
public final CiRegisterConfig trapStub;
/**
* The register configuration for the {@linkplain Stubs#genUncommonTrapStub() uncommon trap stub}.
*/
public final CiRegisterConfig uncommonTrapStub;
public CiRegisterConfig getRegisterConfig(ClassMethodActor method) {
if (method.isVmEntryPoint()) {
return n2j;
}
if (method.isTemplate()) {
return bytecodeTemplate;
}
return standard;
}
@HOSTED_ONLY
public RegisterConfigs(
CiRegisterConfig standard,
CiRegisterConfig n2j,
CiRegisterConfig trampoline,
CiRegisterConfig template,
CiRegisterConfig compilerStub,
CiRegisterConfig uncommonTrapStub,
CiRegisterConfig trapStub) {
this.standard = standard;
this.n2j = n2j;
this.trampoline = trampoline;
this.bytecodeTemplate = template;
this.compilerStub = compilerStub;
this.uncommonTrapStub = uncommonTrapStub;
this.trapStub = trapStub;
assert Arrays.equals(standard.getAllocatableRegisters(), standard.getCallerSaveRegisters()) : "VM requires caller-save for VM to VM calls";
}
@HOSTED_ONLY
private static void setNonZero(RiRegisterAttributes[] attrMap, CiRegister... regs) {
for (CiRegister reg : regs) {
attrMap[reg.number].isNonZero = true;
}
}
@HOSTED_ONLY
public static RegisterConfigs create() {
if (platform().isa == ISA.AMD64) {
OS os = platform().os;
if (os == OS.LINUX || os == OS.SOLARIS || os == OS.DARWIN || os == OS.MAXVE) {
/**
* The set of allocatable registers shared by most register configurations.
*/
CiRegister[] allocatable = {
rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r10, r12, r13, r15,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15};
CiRegister[] parameters = {
rdi, rsi, rdx, rcx, r8, r9,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
};
// A call to the runtime may change the state of the safepoint latch
// and so a compiler stub must leave the latch register alone
CiRegister[] allRegistersExceptLatch = {
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi,
r8, r9, r10, r11, r12, r13, /*r14,*/ r15,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
};
HashMap<Integer, CiRegister> roleMap = new HashMap<Integer, CiRegister>();
roleMap.put(CPU_SP, rsp);
roleMap.put(CPU_FP, rbp);
roleMap.put(ABI_SP, rsp);
roleMap.put(ABI_FP, rsp);
roleMap.put(LATCH, r14);
/**
* The register configuration for a normal Java method.
* This configuration specifies <b>all</b> allocatable registers as caller-saved
* as inlining is expected to reduce the call overhead sufficiently.
*/
CiRegisterConfig standard = new CiRegisterConfig(
rsp, // frame
rax, // integral return value
xmm0, // floating point return value
r11, // scratch
allocatable, // allocatable
allocatable, // caller save
parameters, // parameter registers
null, // no callee save
allRegisters, // all AMD64 registers
roleMap); // VM register role map
// Account for the word at the bottom of the frame used
// for saving an overwritten return address during deoptimization
int javaStackArg0Offset = Deoptimization.DEOPT_RETURN_ADDRESS_OFFSET + Word.size();
int nativeStackArg0Offset = 0;
standard.stackArg0Offsets[JavaCall.ordinal()] = javaStackArg0Offset;
standard.stackArg0Offsets[JavaCallee.ordinal()] = javaStackArg0Offset;
standard.stackArg0Offsets[RuntimeCall.ordinal()] = javaStackArg0Offset;
standard.stackArg0Offsets[NativeCall.ordinal()] = nativeStackArg0Offset;
setNonZero(standard.getAttributesMap(), r14, rsp);
CiRegisterConfig compilerStub = new CiRegisterConfig(standard, new CiCalleeSaveLayout(0, -1, 8, allRegistersExceptLatch));
CiRegisterConfig uncommonTrapStub = new CiRegisterConfig(standard, new CiCalleeSaveLayout(0, -1, 8, cpuxmmRegisters));
CiRegisterConfig trapStub = new CiRegisterConfig(standard, AMD64TrapFrameAccess.CSL);
CiRegisterConfig trampoline = new CiRegisterConfig(standard, new CiCalleeSaveLayout(0, -1, 8,
rdi, rsi, rdx, rcx, r8, r9, // parameters
rbp, // must be preserved for baseline compiler
standard.getScratchRegister(), // dynamic dispatch index is saved here for stack frame walker
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 // parameters
));
CiRegisterConfig n2j = new CiRegisterConfig(standard, new CiCalleeSaveLayout(Integer.MAX_VALUE, -1, 8, rbx, rbp, r12, r13, r14, r15));
n2j.stackArg0Offsets[JavaCallee.ordinal()] = nativeStackArg0Offset;
roleMap.put(ABI_FP, rbp);
CiRegisterConfig template = new CiRegisterConfig(
rbp, // frame
rax, // integral return value
xmm0, // floating point return value
r11, // scratch
allocatable, // allocatable
allocatable, // caller save
parameters, // parameter registers
null, // no callee save
allRegisters, // all AMD64 registers
roleMap); // VM register role map
setNonZero(template.getAttributesMap(), r14, rsp, rbp);
return new RegisterConfigs(standard, n2j, trampoline, template, compilerStub, uncommonTrapStub, trapStub);
}
}
throw FatalError.unimplemented();
}
}