1 /* 2 * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.runtime.sparc; 26 27 import java.util.*; 28 29 import sun.jvm.hotspot.asm.sparc.*; 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.runtime.*; 32 import sun.jvm.hotspot.types.*; 33 import sun.jvm.hotspot.utilities.*; 34 import sun.jvm.hotspot.utilities.Observable; 35 import sun.jvm.hotspot.utilities.Observer; 36 37 public class SPARCRegisterMap extends RegisterMap { 38 /** Register window save area (for L and I regs) */ 39 private Address window; 40 /** Previous save area (for O regs, if needed) */ 41 private Address youngerWindow; 42 43 private static int registerImplNumberOfRegisters; 44 45 // Unified register numbering scheme: each 32-bits counts as a register 46 // number, so all the V9 registers take 2 slots. 47 private static int[] R_L_nums = new int[] {0+040,2+040,4+040,6+040,8+040,10+040,12+040,14+040}; 48 private static int[] R_I_nums = new int[] {0+060,2+060,4+060,6+060,8+060,10+060,12+060,14+060}; 49 private static int[] R_O_nums = new int[] {0+020,2+020,4+020,6+020,8+020,10+020,12+020,14+020}; 50 private static int[] R_G_nums = new int[] {0+000,2+000,4+000,6+000,8+000,10+000,12+000,14+000}; 51 52 private static long badMask; 53 private static long R_LIO_mask; 54 55 private static int sizeofJint; 56 57 static { 58 VM.registerVMInitializedObserver(new Observer() { 59 public void update(Observable o, Object data) { 60 initialize(VM.getVM().getTypeDataBase()); 61 } 62 }); 63 } 64 65 private static void initialize(TypeDataBase db) { 66 badMask = 0; 67 R_LIO_mask = 0; 68 69 sizeofJint = (int) db.lookupType("jint").getSize(); 70 registerImplNumberOfRegisters = db.lookupIntConstant("RegisterImpl::number_of_registers").intValue(); 71 72 for (int i = 0; i < 8; i++) { 73 Assert.that(R_L_nums[i] < locationValidTypeSize, "in first chunk"); 74 Assert.that(R_I_nums[i] < locationValidTypeSize, "in first chunk"); 75 Assert.that(R_O_nums[i] < locationValidTypeSize, "in first chunk"); 76 Assert.that(R_G_nums[i] < locationValidTypeSize, "in first chunk"); 77 } 78 79 badMask |= ((long) 1 << R_O_nums[6]); // SP 80 badMask |= ((long) 1 << R_O_nums[7]); // cPC 81 badMask |= ((long) 1 << R_I_nums[6]); // FP 82 badMask |= ((long) 1 << R_I_nums[7]); // rPC 83 badMask |= ((long) 1 << R_G_nums[2]); // TLS 84 badMask |= ((long) 1 << R_G_nums[7]); // reserved by libthread 85 86 for (int i = 0; i < 8; i++) { 87 R_LIO_mask |= ((long) 1 << R_L_nums[i]); 88 R_LIO_mask |= ((long) 1 << R_I_nums[i]); 89 R_LIO_mask |= ((long) 1 << R_O_nums[i]); 90 } 91 } 92 93 /** This is the only public constructor, and is only called by 94 SolarisSPARCJavaThread */ 95 public SPARCRegisterMap(JavaThread thread, boolean updateMap) { 96 super(thread, updateMap); 97 } 98 99 protected SPARCRegisterMap(RegisterMap map) { 100 super(map); 101 } 102 103 public Object clone() { 104 SPARCRegisterMap retval = new SPARCRegisterMap(this); 105 return retval; 106 } 107 108 protected void clearPD() { 109 if (thread.hasLastJavaFrame()) { 110 Frame fr = thread.getLastFrame(); 111 window = fr.getSP(); 112 } else { 113 window = null; 114 if (VM.getVM().isDebugging()) { 115 Frame fr = thread.getCurrentFrameGuess(); 116 if (fr != null) { 117 window = fr.getSP(); 118 } 119 } 120 } 121 youngerWindow = null; 122 } 123 124 protected Address getLocationPD(VMReg vmreg) { 125 VM vm = VM.getVM(); 126 int regname = vmreg.getValue(); 127 if (Assert.ASSERTS_ENABLED) { 128 Assert.that(0 <= regname && regname < regCount, "sanity check"); 129 } 130 131 // Only the GPRs get handled this way 132 if (regname >= (registerImplNumberOfRegisters << 1)) { 133 return null; 134 } 135 136 // don't talk about bad registers 137 if ((badMask & ((long) 1 << regname)) != 0) { 138 return null; 139 } 140 141 // Convert to a GPR 142 int secondWord = 0; 143 // 32-bit registers for in, out and local 144 if (!isEven(regname)) { 145 if (vm.isLP64()) { 146 secondWord = sizeofJint; 147 } else { 148 return null; 149 } 150 } 151 152 SPARCRegister reg = new SPARCRegister(regname >> 1); 153 if (reg.isOut()) { 154 if (Assert.ASSERTS_ENABLED) { 155 Assert.that(youngerWindow != null, "Younger window should be available"); 156 } 157 return youngerWindow.addOffsetTo(reg.afterSave().spOffsetInSavedWindow() + secondWord); 158 } 159 if (reg.isLocal() || reg.isIn()) { 160 if (Assert.ASSERTS_ENABLED) { 161 Assert.that(window != null, "Window should be available"); 162 } 163 return window.addOffsetTo(reg.spOffsetInSavedWindow() + secondWord); 164 } 165 166 // Only the window'd GPRs get handled this way; not the globals. 167 return null; 168 } 169 170 protected void initializePD() { 171 window = null; 172 youngerWindow = null; 173 // avoid the shift_individual_registers game 174 makeIntegerRegsUnsaved(); 175 } 176 177 protected void initializeFromPD(RegisterMap map) { 178 SPARCRegisterMap srm = (SPARCRegisterMap) map; 179 window = srm.window; 180 youngerWindow = srm.youngerWindow; 181 // avoid the shift_individual_registers game 182 makeIntegerRegsUnsaved(); 183 } 184 185 public void shiftWindow(Address sp, Address youngerSP) { 186 window = sp; 187 youngerWindow = youngerSP; 188 // Throw away locations for %i, %o, and %l registers: 189 // But do not throw away %g register locs. 190 if (locationValid[0] != 0) { 191 shiftIndividualRegisters(); 192 } 193 } 194 195 /** When popping out of compiled frames, we make all IRegs disappear. */ 196 public void makeIntegerRegsUnsaved() { 197 locationValid[0] = 0; 198 } 199 200 //-------------------------------------------------------------------------------- 201 // Internals only below this point 202 // 203 204 private void shiftIndividualRegisters() { 205 if (!getUpdateMap()) { 206 return; 207 } 208 209 checkLocationValid(); 210 211 long lv = locationValid[0]; 212 long lv0 = lv; 213 214 lv &= ~R_LIO_mask; // clear %l, %o, %i regs 215 216 // if we cleared some non-%g locations, we may have to do some shifting 217 if (lv != lv0) { 218 // copy %i0-%i5 to %o0-%o5, if they have special locations 219 // This can happen in within stubs which spill argument registers 220 // around a dynamic link operation, such as resolve_opt_virtual_call. 221 for (int i = 0; i < 8; i++) { 222 if ((lv0 & ((long) 1 << R_I_nums[i])) != 0) { 223 location[R_O_nums[i]] = location[R_I_nums[i]]; 224 lv |= ((long) 1 << R_O_nums[i]); 225 } 226 } 227 } 228 229 locationValid[0] = lv; 230 checkLocationValid(); 231 } 232 233 private boolean isEven(int i) { 234 return (i & 1) == 0; 235 } 236 237 private void checkLocationValid() { 238 if (Assert.ASSERTS_ENABLED) { 239 Assert.that((locationValid[0] & badMask) == 0, "cannot have special locations for SP,FP,TLS,etc."); 240 } 241 } 242 }