| /* |
| * Copyright (c) 2000, 2005, 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 sun.jvm.hotspot.runtime.sparc; |
| |
| import java.util.*; |
| |
| import sun.jvm.hotspot.asm.sparc.*; |
| import sun.jvm.hotspot.debugger.*; |
| import sun.jvm.hotspot.runtime.*; |
| import sun.jvm.hotspot.types.*; |
| import sun.jvm.hotspot.utilities.*; |
| |
| public class SPARCRegisterMap extends RegisterMap { |
| /** Register window save area (for L and I regs) */ |
| private Address window; |
| /** Previous save area (for O regs, if needed) */ |
| private Address youngerWindow; |
| |
| private static int registerImplNumberOfRegisters; |
| |
| // Unified register numbering scheme: each 32-bits counts as a register |
| // number, so all the V9 registers take 2 slots. |
| private static int[] R_L_nums = new int[] {0+040,2+040,4+040,6+040,8+040,10+040,12+040,14+040}; |
| private static int[] R_I_nums = new int[] {0+060,2+060,4+060,6+060,8+060,10+060,12+060,14+060}; |
| private static int[] R_O_nums = new int[] {0+020,2+020,4+020,6+020,8+020,10+020,12+020,14+020}; |
| private static int[] R_G_nums = new int[] {0+000,2+000,4+000,6+000,8+000,10+000,12+000,14+000}; |
| |
| private static long badMask; |
| private static long R_LIO_mask; |
| |
| private static int sizeofJint; |
| |
| static { |
| VM.registerVMInitializedObserver(new Observer() { |
| public void update(Observable o, Object data) { |
| initialize(VM.getVM().getTypeDataBase()); |
| } |
| }); |
| } |
| |
| private static void initialize(TypeDataBase db) { |
| badMask = 0; |
| R_LIO_mask = 0; |
| |
| sizeofJint = (int) db.lookupType("jint").getSize(); |
| registerImplNumberOfRegisters = db.lookupIntConstant("RegisterImpl::number_of_registers").intValue(); |
| |
| for (int i = 0; i < 8; i++) { |
| Assert.that(R_L_nums[i] < locationValidTypeSize, "in first chunk"); |
| Assert.that(R_I_nums[i] < locationValidTypeSize, "in first chunk"); |
| Assert.that(R_O_nums[i] < locationValidTypeSize, "in first chunk"); |
| Assert.that(R_G_nums[i] < locationValidTypeSize, "in first chunk"); |
| } |
| |
| badMask |= ((long) 1 << R_O_nums[6]); // SP |
| badMask |= ((long) 1 << R_O_nums[7]); // cPC |
| badMask |= ((long) 1 << R_I_nums[6]); // FP |
| badMask |= ((long) 1 << R_I_nums[7]); // rPC |
| badMask |= ((long) 1 << R_G_nums[2]); // TLS |
| badMask |= ((long) 1 << R_G_nums[7]); // reserved by libthread |
| |
| for (int i = 0; i < 8; i++) { |
| R_LIO_mask |= ((long) 1 << R_L_nums[i]); |
| R_LIO_mask |= ((long) 1 << R_I_nums[i]); |
| R_LIO_mask |= ((long) 1 << R_O_nums[i]); |
| } |
| } |
| |
| /** This is the only public constructor, and is only called by |
| SolarisSPARCJavaThread */ |
| public SPARCRegisterMap(JavaThread thread, boolean updateMap) { |
| super(thread, updateMap); |
| } |
| |
| protected SPARCRegisterMap(RegisterMap map) { |
| super(map); |
| } |
| |
| public Object clone() { |
| SPARCRegisterMap retval = new SPARCRegisterMap(this); |
| return retval; |
| } |
| |
| protected void clearPD() { |
| if (thread.hasLastJavaFrame()) { |
| Frame fr = thread.getLastFrame(); |
| window = fr.getSP(); |
| } else { |
| window = null; |
| if (VM.getVM().isDebugging()) { |
| Frame fr = thread.getCurrentFrameGuess(); |
| if (fr != null) { |
| window = fr.getSP(); |
| } |
| } |
| } |
| youngerWindow = null; |
| } |
| |
| protected Address getLocationPD(VMReg vmreg) { |
| VM vm = VM.getVM(); |
| int regname = vmreg.getValue(); |
| if (Assert.ASSERTS_ENABLED) { |
| Assert.that(0 <= regname && regname < regCount, "sanity check"); |
| } |
| |
| // Only the GPRs get handled this way |
| if (regname >= (registerImplNumberOfRegisters << 1)) { |
| return null; |
| } |
| |
| // don't talk about bad registers |
| if ((badMask & ((long) 1 << regname)) != 0) { |
| return null; |
| } |
| |
| // Convert to a GPR |
| int secondWord = 0; |
| // 32-bit registers for in, out and local |
| if (!isEven(regname)) { |
| if (vm.isLP64()) { |
| secondWord = sizeofJint; |
| } else { |
| return null; |
| } |
| } |
| |
| SPARCRegister reg = new SPARCRegister(regname >> 1); |
| if (reg.isOut()) { |
| if (Assert.ASSERTS_ENABLED) { |
| Assert.that(youngerWindow != null, "Younger window should be available"); |
| } |
| return youngerWindow.addOffsetTo(reg.afterSave().spOffsetInSavedWindow() + secondWord); |
| } |
| if (reg.isLocal() || reg.isIn()) { |
| if (Assert.ASSERTS_ENABLED) { |
| Assert.that(window != null, "Window should be available"); |
| } |
| return window.addOffsetTo(reg.spOffsetInSavedWindow() + secondWord); |
| } |
| |
| // Only the window'd GPRs get handled this way; not the globals. |
| return null; |
| } |
| |
| protected void initializePD() { |
| window = null; |
| youngerWindow = null; |
| // avoid the shift_individual_registers game |
| makeIntegerRegsUnsaved(); |
| } |
| |
| protected void initializeFromPD(RegisterMap map) { |
| SPARCRegisterMap srm = (SPARCRegisterMap) map; |
| window = srm.window; |
| youngerWindow = srm.youngerWindow; |
| // avoid the shift_individual_registers game |
| makeIntegerRegsUnsaved(); |
| } |
| |
| public void shiftWindow(Address sp, Address youngerSP) { |
| window = sp; |
| youngerWindow = youngerSP; |
| // Throw away locations for %i, %o, and %l registers: |
| // But do not throw away %g register locs. |
| if (locationValid[0] != 0) { |
| shiftIndividualRegisters(); |
| } |
| } |
| |
| /** When popping out of compiled frames, we make all IRegs disappear. */ |
| public void makeIntegerRegsUnsaved() { |
| locationValid[0] = 0; |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // Internals only below this point |
| // |
| |
| private void shiftIndividualRegisters() { |
| if (!getUpdateMap()) { |
| return; |
| } |
| |
| checkLocationValid(); |
| |
| long lv = locationValid[0]; |
| long lv0 = lv; |
| |
| lv &= ~R_LIO_mask; // clear %l, %o, %i regs |
| |
| // if we cleared some non-%g locations, we may have to do some shifting |
| if (lv != lv0) { |
| // copy %i0-%i5 to %o0-%o5, if they have special locations |
| // This can happen in within stubs which spill argument registers |
| // around a dynamic link operation, such as resolve_opt_virtual_call. |
| for (int i = 0; i < 8; i++) { |
| if ((lv0 & ((long) 1 << R_I_nums[i])) != 0) { |
| location[R_O_nums[i]] = location[R_I_nums[i]]; |
| lv |= ((long) 1 << R_O_nums[i]); |
| } |
| } |
| } |
| |
| locationValid[0] = lv; |
| checkLocationValid(); |
| } |
| |
| private boolean isEven(int i) { |
| return (i & 1) == 0; |
| } |
| |
| private void checkLocationValid() { |
| if (Assert.ASSERTS_ENABLED) { |
| Assert.that((locationValid[0] & badMask) == 0, "cannot have special locations for SP,FP,TLS,etc."); |
| } |
| } |
| } |