88 @Override 89 public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) { 90 ArrayList<Register> list = new ArrayList<>(); 91 for (Register reg : registers) { 92 if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) { 93 list.add(reg); 94 } 95 } 96 97 RegisterArray ret = new RegisterArray(list); 98 return ret; 99 } 100 101 @Override 102 public RegisterAttributes[] getAttributesMap() { 103 return attributesMap.clone(); 104 } 105 106 private final RegisterArray javaGeneralParameterRegisters; 107 private final RegisterArray nativeGeneralParameterRegisters; 108 private final RegisterArray xmmParameterRegisters = new RegisterArray(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7); 109 110 /* 111 * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack 112 * to store the argument registers 113 */ 114 private final boolean needsNativeStackHomeSpace; 115 116 private static final RegisterArray reservedRegisters = new RegisterArray(rsp, r15); 117 118 private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) { 119 RegisterArray allRegisters = arch.getAvailableValueRegisters(); 120 Register[] registers = new Register[allRegisters.size() - reservedRegisters.size() - (reserveForHeapBase ? 1 : 0)]; 121 List<Register> reservedRegistersList = reservedRegisters.asList(); 122 123 int idx = 0; 124 for (Register reg : allRegisters) { 125 if (reservedRegistersList.contains(reg)) { 126 // skip reserved registers 127 continue; 128 } 129 if (reserveForHeapBase && reg.equals(r12)) { 130 // skip heap base register 131 continue; 132 } 133 134 registers[idx++] = reg; 135 } 136 137 assert idx == registers.length; 138 return new RegisterArray(registers); 139 } 140 141 public AMD64HotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops, boolean windowsOs) { 142 this(target, initAllocatable(target.arch, useCompressedOops), windowsOs); 143 assert callerSaved.size() >= allocatable.size(); 144 } 145 146 public AMD64HotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable, boolean windowsOs) { 147 this.target = target; 148 149 if (windowsOs) { 150 javaGeneralParameterRegisters = new RegisterArray(rdx, r8, r9, rdi, rsi, rcx); 151 nativeGeneralParameterRegisters = new RegisterArray(rcx, rdx, r8, r9); 152 this.needsNativeStackHomeSpace = true; 153 } else { 154 javaGeneralParameterRegisters = new RegisterArray(rsi, rdx, rcx, r8, r9, rdi); 155 nativeGeneralParameterRegisters = new RegisterArray(rdi, rsi, rdx, rcx, r8, r9); 156 this.needsNativeStackHomeSpace = false; 157 } 158 159 this.allocatable = allocatable; 160 Set<Register> callerSaveSet = new HashSet<>(); 161 allocatable.addTo(callerSaveSet); 162 xmmParameterRegisters.addTo(callerSaveSet); 163 callerSaveSet.addAll(javaGeneralParameterRegisters.asList()); 164 nativeGeneralParameterRegisters.addTo(callerSaveSet); 165 callerSaved = new RegisterArray(callerSaveSet); 166 167 allAllocatableAreCallerSaved = true; 168 attributesMap = RegisterAttributes.createMap(this, target.arch.getRegisters()); 169 } 170 171 @Override 172 public RegisterArray getCallerSaveRegisters() { 173 return callerSaved; 174 } 175 176 @Override 177 public RegisterArray getCalleeSaveRegisters() { 178 return null; 179 } 180 181 @Override 182 public boolean areAllAllocatableRegistersCallerSaved() { 183 return allAllocatableAreCallerSaved; 184 } 185 186 @Override 187 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory<?> valueKindFactory) { 188 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; 189 if (type == HotSpotCallingConventionType.NativeCall) { 190 return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); 191 } 192 // On x64, parameter locations are the same whether viewed 193 // from the caller or callee perspective 194 return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); 195 } 196 197 @Override 198 public RegisterArray getCallingConventionRegisters(Type type, JavaKind kind) { 199 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; 200 switch (kind) { 201 case Boolean: 202 case Byte: 203 case Short: 204 case Char: 205 case Int: 206 case Long: 207 case Object: 208 return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; 209 case Float: 210 case Double: 211 return xmmParameterRegisters; 212 default: 213 throw JVMCIError.shouldNotReachHere(); 214 } 215 } 216 217 private CallingConvention callingConvention(RegisterArray generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, HotSpotCallingConventionType type, 218 ValueKindFactory<?> valueKindFactory) { 219 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; 220 221 int currentGeneral = 0; 222 int currentXMM = 0; 223 int currentStackOffset = type == HotSpotCallingConventionType.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.size() * target.wordSize : 0; 224 225 for (int i = 0; i < parameterTypes.length; i++) { 226 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); 227 228 switch (kind) { 229 case Byte: 230 case Boolean: 231 case Short: 232 case Char: 233 case Int: 234 case Long: 235 case Object: 236 if (currentGeneral < generalParameterRegisters.size()) { 237 Register register = generalParameterRegisters.get(currentGeneral++); 238 locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); 239 } 240 break; 241 case Float: 242 case Double: 243 if (currentXMM < xmmParameterRegisters.size()) { 244 Register register = xmmParameterRegisters.get(currentXMM++); 245 locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); 246 } 247 break; 248 default: 249 throw JVMCIError.shouldNotReachHere(); 250 } 251 252 if (locations[i] == null) { 253 ValueKind<?> valueKind = valueKindFactory.getValueKind(kind); 254 locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.out); 255 currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize); 256 } 257 } 258 259 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); 260 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind())); 261 return new CallingConvention(currentStackOffset, returnLocation, locations); 262 } 263 264 @Override 265 public Register getReturnRegister(JavaKind kind) { 266 switch (kind) { 267 case Boolean: 268 case Byte: 269 case Char: 270 case Short: 271 case Int: 272 case Long: 273 case Object: 274 return rax; 275 case Float: 276 case Double: 277 return xmm0; | 88 @Override 89 public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) { 90 ArrayList<Register> list = new ArrayList<>(); 91 for (Register reg : registers) { 92 if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) { 93 list.add(reg); 94 } 95 } 96 97 RegisterArray ret = new RegisterArray(list); 98 return ret; 99 } 100 101 @Override 102 public RegisterAttributes[] getAttributesMap() { 103 return attributesMap.clone(); 104 } 105 106 private final RegisterArray javaGeneralParameterRegisters; 107 private final RegisterArray nativeGeneralParameterRegisters; 108 private final RegisterArray javaXMMParameterRegisters; 109 private final RegisterArray nativeXMMParameterRegisters; 110 private final boolean windowsOS; 111 112 /* 113 * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack 114 * to store the argument registers 115 */ 116 private final boolean needsNativeStackHomeSpace; 117 118 private static final RegisterArray reservedRegisters = new RegisterArray(rsp, r15); 119 120 private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) { 121 RegisterArray allRegisters = arch.getAvailableValueRegisters(); 122 Register[] registers = new Register[allRegisters.size() - reservedRegisters.size() - (reserveForHeapBase ? 1 : 0)]; 123 List<Register> reservedRegistersList = reservedRegisters.asList(); 124 125 int idx = 0; 126 for (Register reg : allRegisters) { 127 if (reservedRegistersList.contains(reg)) { 128 // skip reserved registers 129 continue; 130 } 131 if (reserveForHeapBase && reg.equals(r12)) { 132 // skip heap base register 133 continue; 134 } 135 136 registers[idx++] = reg; 137 } 138 139 assert idx == registers.length; 140 return new RegisterArray(registers); 141 } 142 143 public AMD64HotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops, boolean windowsOs) { 144 this(target, initAllocatable(target.arch, useCompressedOops), windowsOs); 145 assert callerSaved.size() >= allocatable.size(); 146 } 147 148 public AMD64HotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable, boolean windowsOS) { 149 this.target = target; 150 this.windowsOS = windowsOS; 151 152 if (windowsOS) { 153 javaGeneralParameterRegisters = new RegisterArray(rdx, r8, r9, rdi, rsi, rcx); 154 nativeGeneralParameterRegisters = new RegisterArray(rcx, rdx, r8, r9); 155 nativeXMMParameterRegisters = new RegisterArray(xmm0, xmm1, xmm2, xmm3); 156 this.needsNativeStackHomeSpace = true; 157 } else { 158 javaGeneralParameterRegisters = new RegisterArray(rsi, rdx, rcx, r8, r9, rdi); 159 nativeGeneralParameterRegisters = new RegisterArray(rdi, rsi, rdx, rcx, r8, r9); 160 nativeXMMParameterRegisters = new RegisterArray(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7); 161 this.needsNativeStackHomeSpace = false; 162 } 163 javaXMMParameterRegisters = new RegisterArray(xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7); 164 165 this.allocatable = allocatable; 166 Set<Register> callerSaveSet = new HashSet<>(); 167 allocatable.addTo(callerSaveSet); 168 javaXMMParameterRegisters.addTo(callerSaveSet); 169 callerSaveSet.addAll(javaGeneralParameterRegisters.asList()); 170 nativeGeneralParameterRegisters.addTo(callerSaveSet); 171 callerSaved = new RegisterArray(callerSaveSet); 172 173 allAllocatableAreCallerSaved = true; 174 attributesMap = RegisterAttributes.createMap(this, target.arch.getRegisters()); 175 } 176 177 @Override 178 public RegisterArray getCallerSaveRegisters() { 179 return callerSaved; 180 } 181 182 @Override 183 public RegisterArray getCalleeSaveRegisters() { 184 return null; 185 } 186 187 @Override 188 public boolean areAllAllocatableRegistersCallerSaved() { 189 return allAllocatableAreCallerSaved; 190 } 191 192 @Override 193 public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory<?> valueKindFactory) { 194 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; 195 if (type == HotSpotCallingConventionType.NativeCall) { 196 return callingConvention(nativeGeneralParameterRegisters, nativeXMMParameterRegisters, windowsOS, returnType, parameterTypes, hotspotType, valueKindFactory); 197 } 198 // On x64, parameter locations are the same whether viewed 199 // from the caller or callee perspective 200 return callingConvention(javaGeneralParameterRegisters, javaXMMParameterRegisters, false, returnType, parameterTypes, hotspotType, valueKindFactory); 201 } 202 203 @Override 204 public RegisterArray getCallingConventionRegisters(Type type, JavaKind kind) { 205 HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; 206 switch (kind) { 207 case Boolean: 208 case Byte: 209 case Short: 210 case Char: 211 case Int: 212 case Long: 213 case Object: 214 return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; 215 case Float: 216 case Double: 217 return hotspotType == HotSpotCallingConventionType.NativeCall ? nativeXMMParameterRegisters : javaXMMParameterRegisters; 218 default: 219 throw JVMCIError.shouldNotReachHere(); 220 } 221 } 222 223 /** 224 * Hand out registers matching the calling convention from the {@code generalParameterRegisters} 225 * and {@code xmmParameterRegisters} sets. Normally registers are handed out from each set 226 * individually based on the type of the argument. If the {@code unified} flag is true then hand 227 * out registers in a single sequence, selecting between the sets based on the type. This is to 228 * support the Windows calling convention which only ever passes 4 arguments in registers, no 229 * matter their types. 230 * 231 * @param generalParameterRegisters 232 * @param xmmParameterRegisters 233 * @param unified 234 * @param returnType 235 * @param parameterTypes 236 * @param type 237 * @param valueKindFactory 238 * @return the resulting calling convention 239 */ 240 private CallingConvention callingConvention(RegisterArray generalParameterRegisters, RegisterArray xmmParameterRegisters, boolean unified, JavaType returnType, JavaType[] parameterTypes, 241 HotSpotCallingConventionType type, 242 ValueKindFactory<?> valueKindFactory) { 243 assert !unified || generalParameterRegisters.size() == xmmParameterRegisters.size() : "must be same size in unified mode"; 244 AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; 245 246 int currentGeneral = 0; 247 int currentXMM = 0; 248 int currentStackOffset = type == HotSpotCallingConventionType.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.size() * target.wordSize : 0; 249 250 for (int i = 0; i < parameterTypes.length; i++) { 251 final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); 252 253 switch (kind) { 254 case Byte: 255 case Boolean: 256 case Short: 257 case Char: 258 case Int: 259 case Long: 260 case Object: 261 if (currentGeneral < generalParameterRegisters.size()) { 262 Register register = generalParameterRegisters.get(currentGeneral++); 263 locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); 264 } 265 break; 266 case Float: 267 case Double: 268 if ((unified ? currentGeneral : currentXMM) < xmmParameterRegisters.size()) { 269 Register register = xmmParameterRegisters.get(unified ? currentGeneral++ : currentXMM++); 270 locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); 271 } 272 break; 273 default: 274 throw JVMCIError.shouldNotReachHere(); 275 } 276 277 if (locations[i] == null) { 278 ValueKind<?> valueKind = valueKindFactory.getValueKind(kind); 279 locations[i] = StackSlot.get(valueKind, currentStackOffset, !type.out); 280 currentStackOffset += Math.max(valueKind.getPlatformKind().getSizeInBytes(), target.wordSize); 281 } 282 } 283 assert !unified || currentXMM == 0 : "shouldn't be used in unified mode"; 284 285 JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); 286 AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(valueKindFactory.getValueKind(returnKind.getStackKind())); 287 return new CallingConvention(currentStackOffset, returnLocation, locations); 288 } 289 290 @Override 291 public Register getReturnRegister(JavaKind kind) { 292 switch (kind) { 293 case Boolean: 294 case Byte: 295 case Char: 296 case Short: 297 case Int: 298 case Long: 299 case Object: 300 return rax; 301 case Float: 302 case Double: 303 return xmm0; |