001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.compilers.opt.hir2lir; 014 015 import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_ADDRESS; 016 import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_INT; 017 import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI; 018 import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH; 019 import static org.jikesrvm.compilers.opt.ir.Operators.BOUNDS_CHECK_opcode; 020 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ALOAD_opcode; 021 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_ASTORE_opcode; 022 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_LOAD; 023 import static org.jikesrvm.compilers.opt.ir.Operators.BYTE_STORE; 024 import static org.jikesrvm.compilers.opt.ir.Operators.CALL; 025 import static org.jikesrvm.compilers.opt.ir.Operators.CALL_opcode; 026 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_NOTNULL_opcode; 027 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_UNRESOLVED_opcode; 028 import static org.jikesrvm.compilers.opt.ir.Operators.CHECKCAST_opcode; 029 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD_opcode; 030 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE_opcode; 031 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD; 032 import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE; 033 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ALOAD_opcode; 034 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_ASTORE_opcode; 035 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_LOAD; 036 import static org.jikesrvm.compilers.opt.ir.Operators.FLOAT_STORE; 037 import static org.jikesrvm.compilers.opt.ir.Operators.GETFIELD_opcode; 038 import static org.jikesrvm.compilers.opt.ir.Operators.GETSTATIC_opcode; 039 import static org.jikesrvm.compilers.opt.ir.Operators.GET_CLASS_TIB; 040 import static org.jikesrvm.compilers.opt.ir.Operators.GET_OBJ_TIB; 041 import static org.jikesrvm.compilers.opt.ir.Operators.GOTO; 042 import static org.jikesrvm.compilers.opt.ir.Operators.IG_CLASS_TEST_opcode; 043 import static org.jikesrvm.compilers.opt.ir.Operators.IG_METHOD_TEST_opcode; 044 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_NOTNULL_opcode; 045 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_UNRESOLVED_opcode; 046 import static org.jikesrvm.compilers.opt.ir.Operators.INSTANCEOF_opcode; 047 import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRSigExt; 048 import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt; 049 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ADD; 050 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ALOAD_opcode; 051 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ASTORE_opcode; 052 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP; 053 import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2; 054 import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; 055 import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL; 056 import static org.jikesrvm.compilers.opt.ir.Operators.INT_STORE; 057 import static org.jikesrvm.compilers.opt.ir.Operators.INT_ZERO_CHECK_opcode; 058 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ALOAD_opcode; 059 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ASTORE_opcode; 060 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_LOAD; 061 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_STORE; 062 import static org.jikesrvm.compilers.opt.ir.Operators.LONG_ZERO_CHECK_opcode; 063 import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH; 064 import static org.jikesrvm.compilers.opt.ir.Operators.LOOKUPSWITCH_opcode; 065 import static org.jikesrvm.compilers.opt.ir.Operators.LOWTABLESWITCH; 066 import static org.jikesrvm.compilers.opt.ir.Operators.MUST_IMPLEMENT_INTERFACE_opcode; 067 import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_NOTNULL_opcode; 068 import static org.jikesrvm.compilers.opt.ir.Operators.OBJARRAY_STORE_CHECK_opcode; 069 import static org.jikesrvm.compilers.opt.ir.Operators.PUTFIELD_opcode; 070 import static org.jikesrvm.compilers.opt.ir.Operators.PUTSTATIC_opcode; 071 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD_opcode; 072 import static org.jikesrvm.compilers.opt.ir.Operators.REF_ASTORE_opcode; 073 import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP; 074 import static org.jikesrvm.compilers.opt.ir.Operators.REF_LOAD; 075 import static org.jikesrvm.compilers.opt.ir.Operators.REF_STORE; 076 import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE; 077 import static org.jikesrvm.compilers.opt.ir.Operators.RESOLVE_MEMBER_opcode; 078 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ALOAD_opcode; 079 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_ASTORE_opcode; 080 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_LOAD; 081 import static org.jikesrvm.compilers.opt.ir.Operators.SHORT_STORE; 082 import static org.jikesrvm.compilers.opt.ir.Operators.SYSCALL_opcode; 083 import static org.jikesrvm.compilers.opt.ir.Operators.TABLESWITCH_opcode; 084 import static org.jikesrvm.compilers.opt.ir.Operators.TRAP_IF; 085 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_ALOAD_opcode; 086 import static org.jikesrvm.compilers.opt.ir.Operators.UBYTE_LOAD; 087 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD_opcode; 088 import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD; 089 import static org.jikesrvm.objectmodel.TIBLayoutConstants.NEEDS_DYNAMIC_LINK; 090 import static org.jikesrvm.objectmodel.TIBLayoutConstants.TIB_INTERFACE_DISPATCH_TABLE_INDEX; 091 092 import org.jikesrvm.VM; 093 import org.jikesrvm.adaptive.AosEntrypoints; 094 import org.jikesrvm.classloader.RVMClass; 095 import org.jikesrvm.classloader.RVMField; 096 import org.jikesrvm.classloader.InterfaceInvocation; 097 import org.jikesrvm.classloader.InterfaceMethodSignature; 098 import org.jikesrvm.classloader.RVMMethod; 099 import org.jikesrvm.classloader.RVMType; 100 import org.jikesrvm.classloader.TypeReference; 101 import org.jikesrvm.compilers.opt.OptOptions; 102 import org.jikesrvm.compilers.opt.controlflow.BranchOptimizations; 103 import org.jikesrvm.compilers.opt.ir.ALoad; 104 import org.jikesrvm.compilers.opt.ir.AStore; 105 import org.jikesrvm.compilers.opt.ir.BasicBlock; 106 import org.jikesrvm.compilers.opt.ir.Binary; 107 import org.jikesrvm.compilers.opt.ir.BoundsCheck; 108 import org.jikesrvm.compilers.opt.ir.CacheOp; 109 import org.jikesrvm.compilers.opt.ir.Call; 110 import org.jikesrvm.compilers.opt.ir.GetField; 111 import org.jikesrvm.compilers.opt.ir.GetStatic; 112 import org.jikesrvm.compilers.opt.ir.Goto; 113 import org.jikesrvm.compilers.opt.ir.GuardedUnary; 114 import org.jikesrvm.compilers.opt.ir.IR; 115 import org.jikesrvm.compilers.opt.ir.IRTools; 116 import org.jikesrvm.compilers.opt.ir.IfCmp; 117 import org.jikesrvm.compilers.opt.ir.IfCmp2; 118 import org.jikesrvm.compilers.opt.ir.InlineGuard; 119 import org.jikesrvm.compilers.opt.ir.Instruction; 120 import org.jikesrvm.compilers.opt.ir.Load; 121 import org.jikesrvm.compilers.opt.ir.LookupSwitch; 122 import org.jikesrvm.compilers.opt.ir.LowTableSwitch; 123 import org.jikesrvm.compilers.opt.ir.Operator; 124 import org.jikesrvm.compilers.opt.ir.PutField; 125 import org.jikesrvm.compilers.opt.ir.PutStatic; 126 import org.jikesrvm.compilers.opt.ir.Store; 127 import org.jikesrvm.compilers.opt.ir.TableSwitch; 128 import org.jikesrvm.compilers.opt.ir.TrapIf; 129 import org.jikesrvm.compilers.opt.ir.Unary; 130 import org.jikesrvm.compilers.opt.ir.ZeroCheck; 131 import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 132 import org.jikesrvm.compilers.opt.ir.operand.BranchOperand; 133 import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand; 134 import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand; 135 import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 136 import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 137 import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 138 import org.jikesrvm.compilers.opt.ir.operand.Operand; 139 import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 140 import org.jikesrvm.compilers.opt.ir.operand.TIBConstantOperand; 141 import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 142 import org.jikesrvm.compilers.opt.ir.operand.TypeOperand; 143 import org.jikesrvm.compilers.opt.specialization.SpecializedMethod; 144 import org.jikesrvm.mm.mminterface.MemoryManagerConstants; 145 import org.jikesrvm.runtime.Entrypoints; 146 import org.jikesrvm.runtime.Magic; 147 import org.vmmagic.unboxed.Address; 148 import org.vmmagic.unboxed.Offset; 149 150 /** 151 * Converts all remaining instructions with HIR-only operators into 152 * an equivalent sequence of LIR operators. 153 */ 154 public abstract class ConvertToLowLevelIR extends IRTools { 155 156 /** 157 * We have slightly different ideas of what the LIR should look like 158 * for IA32 and PowerPC. The main difference is that for IA32 159 * instead of bending over backwards in BURS to rediscover array 160 * loads, (where we can use base + index*scale addressing modes), 161 * we'll leave array loads in the LIR. 162 */ 163 public static final boolean LOWER_ARRAY_ACCESS = VM.BuildForPowerPC; 164 165 /** 166 * Converts the given HIR to LIR. 167 * 168 * @param ir IR to convert 169 */ 170 static void convert(IR ir, OptOptions options) { 171 boolean didArrayStoreCheck = false; 172 for (Instruction s = ir.firstInstructionInCodeOrder(); s != null; s = s.nextInstructionInCodeOrder()) { 173 174 switch (s.getOpcode()) { 175 case GETSTATIC_opcode: { 176 LocationOperand loc = GetStatic.getClearLocation(s); 177 RegisterOperand result = GetStatic.getClearResult(s); 178 Operand address = ir.regpool.makeJTOCOp(ir, s); 179 Operand offset = GetStatic.getClearOffset(s); 180 Load.mutate(s, IRTools.getLoadOp(loc.getFieldRef(), true), result, address, offset, loc); 181 } 182 break; 183 184 case PUTSTATIC_opcode: { 185 LocationOperand loc = PutStatic.getClearLocation(s); 186 Operand value = PutStatic.getClearValue(s); 187 Operand address = ir.regpool.makeJTOCOp(ir, s); 188 Operand offset = PutStatic.getClearOffset(s); 189 Store.mutate(s, IRTools.getStoreOp(loc.getFieldRef(), true), value, address, offset, loc); 190 } 191 break; 192 193 case PUTFIELD_opcode: { 194 LocationOperand loc = PutField.getClearLocation(s); 195 Operand value = PutField.getClearValue(s); 196 Operand address = PutField.getClearRef(s); 197 Operand offset = PutField.getClearOffset(s); 198 Store.mutate(s, 199 IRTools.getStoreOp(loc.getFieldRef(), false), 200 value, 201 address, 202 offset, 203 loc, 204 PutField.getClearGuard(s)); 205 } 206 break; 207 208 case GETFIELD_opcode: { 209 LocationOperand loc = GetField.getClearLocation(s); 210 RegisterOperand result = GetField.getClearResult(s); 211 Operand address = GetField.getClearRef(s); 212 Operand offset = GetField.getClearOffset(s); 213 Load.mutate(s, 214 IRTools.getLoadOp(loc.getFieldRef(), false), 215 result, 216 address, 217 offset, 218 loc, 219 GetField.getClearGuard(s)); 220 } 221 break; 222 223 case INT_ALOAD_opcode: 224 doArrayLoad(s, ir, INT_LOAD, 2); 225 break; 226 227 case LONG_ALOAD_opcode: 228 doArrayLoad(s, ir, LONG_LOAD, 3); 229 break; 230 231 case FLOAT_ALOAD_opcode: 232 doArrayLoad(s, ir, FLOAT_LOAD, 2); 233 break; 234 235 case DOUBLE_ALOAD_opcode: 236 doArrayLoad(s, ir, DOUBLE_LOAD, 3); 237 break; 238 239 case REF_ALOAD_opcode: 240 doArrayLoad(s, ir, REF_LOAD, LOG_BYTES_IN_ADDRESS); 241 break; 242 243 case BYTE_ALOAD_opcode: 244 doArrayLoad(s, ir, BYTE_LOAD, 0); 245 break; 246 247 case UBYTE_ALOAD_opcode: 248 doArrayLoad(s, ir, UBYTE_LOAD, 0); 249 break; 250 251 case USHORT_ALOAD_opcode: 252 doArrayLoad(s, ir, USHORT_LOAD, 1); 253 break; 254 255 case SHORT_ALOAD_opcode: 256 doArrayLoad(s, ir, SHORT_LOAD, 1); 257 break; 258 259 case INT_ASTORE_opcode: 260 doArrayStore(s, ir, INT_STORE, 2); 261 break; 262 263 case LONG_ASTORE_opcode: 264 doArrayStore(s, ir, LONG_STORE, 3); 265 break; 266 267 case FLOAT_ASTORE_opcode: 268 doArrayStore(s, ir, FLOAT_STORE, 2); 269 break; 270 271 case DOUBLE_ASTORE_opcode: 272 doArrayStore(s, ir, DOUBLE_STORE, 3); 273 break; 274 275 case REF_ASTORE_opcode: 276 doArrayStore(s, ir, REF_STORE, LOG_BYTES_IN_ADDRESS); 277 break; 278 279 case BYTE_ASTORE_opcode: 280 doArrayStore(s, ir, BYTE_STORE, 0); 281 break; 282 283 case SHORT_ASTORE_opcode: 284 doArrayStore(s, ir, SHORT_STORE, 1); 285 break; 286 287 case CALL_opcode: 288 s = callHelper(s, ir); 289 break; 290 291 case SYSCALL_opcode: 292 // If the SYSCALL is using a symbolic address, convert that to 293 // a sequence of loads off the BootRecord to find the appropriate field. 294 if (Call.getMethod(s) != null) { 295 expandSysCallTarget(s, ir); 296 } 297 break; 298 299 case TABLESWITCH_opcode: 300 s = tableswitch(s, ir); 301 break; 302 303 case LOOKUPSWITCH_opcode: 304 s = lookup(s, ir); 305 break; 306 307 case OBJARRAY_STORE_CHECK_opcode: 308 s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, true); 309 didArrayStoreCheck = true; 310 break; 311 312 case OBJARRAY_STORE_CHECK_NOTNULL_opcode: 313 s = DynamicTypeCheckExpansion.arrayStoreCheck(s, ir, false); 314 didArrayStoreCheck = true; 315 break; 316 317 case CHECKCAST_opcode: 318 case CHECKCAST_UNRESOLVED_opcode: 319 s = DynamicTypeCheckExpansion.checkcast(s, ir); 320 break; 321 322 case CHECKCAST_NOTNULL_opcode: 323 s = DynamicTypeCheckExpansion.checkcastNotNull(s, ir); 324 break; 325 326 case MUST_IMPLEMENT_INTERFACE_opcode: 327 s = DynamicTypeCheckExpansion.mustImplementInterface(s, ir); 328 break; 329 330 case IG_CLASS_TEST_opcode: 331 IfCmp.mutate(s, 332 REF_IFCMP, 333 ir.regpool.makeTempValidation(), 334 getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s)), 335 getTIB(s, ir, InlineGuard.getGoal(s).asType()), 336 ConditionOperand.NOT_EQUAL(), 337 InlineGuard.getClearTarget(s), 338 InlineGuard.getClearBranchProfile(s)); 339 break; 340 341 case IG_METHOD_TEST_opcode: { 342 MethodOperand methOp = InlineGuard.getClearGoal(s).asMethod(); 343 Operand t1 = getTIB(s, ir, InlineGuard.getClearValue(s), InlineGuard.getClearGuard(s)); 344 Operand t2 = getTIB(s, ir, methOp.getTarget().getDeclaringClass()); 345 IfCmp.mutate(s, 346 REF_IFCMP, 347 ir.regpool.makeTempValidation(), 348 getInstanceMethod(s, ir, t1, methOp.getTarget()), 349 getInstanceMethod(s, ir, t2, methOp.getTarget()), 350 ConditionOperand.NOT_EQUAL(), 351 InlineGuard.getClearTarget(s), 352 InlineGuard.getClearBranchProfile(s)); 353 break; 354 } 355 356 case INSTANCEOF_opcode: 357 case INSTANCEOF_UNRESOLVED_opcode: 358 s = DynamicTypeCheckExpansion.instanceOf(s, ir); 359 break; 360 361 case INSTANCEOF_NOTNULL_opcode: 362 s = DynamicTypeCheckExpansion.instanceOfNotNull(s, ir); 363 break; 364 365 case INT_ZERO_CHECK_opcode: { 366 TrapIf.mutate(s, 367 TRAP_IF, 368 ZeroCheck.getClearGuardResult(s), 369 ZeroCheck.getClearValue(s), 370 IC(0), 371 ConditionOperand.EQUAL(), 372 TrapCodeOperand.DivByZero()); 373 } 374 break; 375 376 case LONG_ZERO_CHECK_opcode: { 377 TrapIf.mutate(s, 378 TRAP_IF, 379 ZeroCheck.getClearGuardResult(s), 380 ZeroCheck.getClearValue(s), 381 LC(0), 382 ConditionOperand.EQUAL(), 383 TrapCodeOperand.DivByZero()); 384 } 385 break; 386 387 case BOUNDS_CHECK_opcode: { 388 // get array_length from array_ref 389 RegisterOperand array_length = 390 InsertGuardedUnary(s, 391 ir, 392 ARRAYLENGTH, 393 TypeReference.Int, 394 BoundsCheck.getClearRef(s), 395 BoundsCheck.getClearGuard(s)); 396 // In UN-signed comparison, a negative index will look like a very 397 // large positive number, greater than array length. 398 // Thus length LLT index is false iff 0 <= index <= length 399 TrapIf.mutate(s, 400 TRAP_IF, 401 BoundsCheck.getClearGuardResult(s), 402 array_length.copyD2U(), 403 BoundsCheck.getClearIndex(s), 404 ConditionOperand.LOWER_EQUAL(), 405 TrapCodeOperand.ArrayBounds()); 406 } 407 break; 408 409 case RESOLVE_MEMBER_opcode: 410 s = resolveMember(s, ir); 411 break; 412 413 default: 414 break; 415 } 416 } 417 // Eliminate possible redundant trap block from array store checks 418 if (didArrayStoreCheck) { 419 branchOpts.perform(ir, true); 420 } 421 } 422 423 private static BranchOptimizations branchOpts = new BranchOptimizations(-1, true, true); 424 425 /** 426 * Expand a tableswitch. 427 * @param s the instruction to expand 428 * @param ir the containing IR 429 * @return the last Instruction in the generated LIR sequence. 430 */ 431 static Instruction tableswitch(Instruction s, IR ir) { 432 433 Instruction s2; 434 int lowLimit = TableSwitch.getLow(s).value; 435 int highLimit = TableSwitch.getHigh(s).value; 436 int number = highLimit - lowLimit + 1; 437 if (VM.VerifyAssertions) { 438 VM._assert(number > 0); // also checks that there are < 2^31 targets 439 } 440 Operand val = TableSwitch.getClearValue(s); 441 BranchOperand defaultLabel = TableSwitch.getClearDefault(s); 442 if (number < ir.options.CONTROL_TABLESWITCH_CUTOFF) { // convert into a lookupswitch 443 Instruction l = 444 LookupSwitch.create(LOOKUPSWITCH, 445 val, 446 null, 447 null, 448 defaultLabel, 449 TableSwitch.getClearDefaultBranchProfile(s), 450 number * 3); 451 for (int i = 0; i < number; i++) { 452 LookupSwitch.setMatch(l, i, IC(lowLimit + i)); 453 LookupSwitch.setTarget(l, i, TableSwitch.getClearTarget(s, i)); 454 LookupSwitch.setBranchProfile(l, i, TableSwitch.getClearBranchProfile(s, i)); 455 } 456 s.insertAfter(CPOS(s, l)); 457 return s.remove(); 458 } 459 RegisterOperand reg = val.asRegister(); 460 BasicBlock BB1 = s.getBasicBlock(); 461 BasicBlock BB2 = BB1.splitNodeAt(s, ir); 462 BasicBlock defaultBB = defaultLabel.target.getBasicBlock(); 463 464 /******* First basic block */ 465 RegisterOperand t; 466 if (lowLimit != 0) { 467 t = insertBinary(s, ir, INT_ADD, TypeReference.Int, reg, IC(-lowLimit)); 468 } else { 469 t = reg.copyU2U(); 470 } 471 BranchProfileOperand defaultProb = TableSwitch.getClearDefaultBranchProfile(s); 472 s.replace(CPOS(s, IfCmp.create(INT_IFCMP, 473 ir.regpool.makeTempValidation(), 474 t, 475 IC(highLimit - lowLimit), 476 ConditionOperand.HIGHER(), 477 defaultLabel, 478 defaultProb))); 479 // Reweight branches to account for the default branch going. If 480 // the default probability was ALWAYS then when we recompute the 481 // weight to be a proportion of the total number of branches. 482 final boolean defaultIsAlways = defaultProb.takenProbability >= 1f; 483 final float weight = defaultIsAlways ? 1f / number : 1f / (1f - defaultProb.takenProbability); 484 485 /********** second Basic Block ******/ 486 s2 = CPOS(s, LowTableSwitch.create(LOWTABLESWITCH, t.copyRO(), number * 2)); 487 boolean containsDefault = false; 488 for (int i = 0; i < number; i++) { 489 BranchOperand b = TableSwitch.getClearTarget(s, i); 490 LowTableSwitch.setTarget(s2, i, b); 491 BranchProfileOperand bp = TableSwitch.getClearBranchProfile(s, i); 492 if (defaultIsAlways) { 493 bp.takenProbability = weight; 494 } else { 495 bp.takenProbability *= weight; 496 } 497 LowTableSwitch.setBranchProfile(s2, i, bp); 498 if (b.target == defaultLabel.target) { 499 containsDefault = true; 500 } 501 } 502 // Fixup the CFG and code order. 503 BB1.insertOut(BB2); 504 BB1.insertOut(defaultBB); 505 ir.cfg.linkInCodeOrder(BB1, BB2); 506 if (!containsDefault) { 507 BB2.deleteOut(defaultBB); 508 } 509 // Simplify a fringe case... 510 // if all targets of the LOWTABLESWITCH are the same, 511 // then just use a GOTO instead of the LOWTABLESWITCH. 512 // This actually happens (very occasionally), and is easy to test for. 513 if (BB2.getNumberOfNormalOut() == 1) { 514 BB2.appendInstruction(CPOS(s, Goto.create(GOTO, LowTableSwitch.getTarget(s2, 0)))); 515 } else { 516 BB2.appendInstruction(s2); 517 } 518 // continue at next BB 519 s = BB2.lastInstruction(); 520 521 return s; 522 } 523 524 /** 525 * Expand a lookupswitch. 526 * @param switchInstr The instruction to expand 527 * @param ir The containing IR 528 * @return the next {@link Instruction} after the generated LIR sequence. 529 */ 530 static Instruction lookup(Instruction switchInstr, IR ir) { 531 Instruction bbend = switchInstr.nextInstructionInCodeOrder(); 532 BasicBlock thisBB = bbend.getBasicBlock(); 533 BasicBlock nextBB = thisBB.nextBasicBlockInCodeOrder(); 534 // Blow away the old Normal ControlFlowGraph edges to prepare for new links 535 thisBB.deleteNormalOut(); 536 switchInstr.remove(); 537 BranchOperand defTarget = LookupSwitch.getClearDefault(switchInstr); 538 BasicBlock defaultBB = defTarget.target.getBasicBlock(); 539 int high = LookupSwitch.getNumberOfTargets(switchInstr) - 1; 540 if (high < 0) { 541 // no cases in switch; just jump to defaultBB 542 thisBB.appendInstruction(Goto.create(GOTO, defTarget)); 543 thisBB.insertOut(defaultBB); 544 } else { 545 Operand match = LookupSwitch.getValue(switchInstr); 546 if (match.isConstant()) { 547 // switch on a constant 548 int value = match.asIntConstant().value; 549 int numMatches = LookupSwitch.getNumberOfMatches(switchInstr); 550 BranchOperand target = LookupSwitch.getDefault(switchInstr); 551 for (int i = 0; i < numMatches; i++) { 552 if (value == LookupSwitch.getMatch(switchInstr, i).value) { 553 target = LookupSwitch.getTarget(switchInstr, i); 554 break; 555 } 556 } 557 thisBB.appendInstruction(Goto.create(GOTO, target)); 558 thisBB.insertOut(target.target.getBasicBlock()); 559 } else { 560 RegisterOperand reg = match.asRegister(); 561 562 // If you're not already at the end of the code order 563 if (nextBB != null) { 564 ir.cfg.breakCodeOrder(thisBB, nextBB); 565 } 566 // generate the binary search tree into thisBB 567 BasicBlock lastNewBB = 568 _lookupswitchHelper(switchInstr, reg, defaultBB, ir, thisBB, 0, high, Integer.MIN_VALUE, Integer.MAX_VALUE); 569 if (nextBB != null) { 570 ir.cfg.linkInCodeOrder(lastNewBB, nextBB); 571 } 572 } 573 } 574 575 // skip all the instrs just inserted by _lookupswitchHelper 576 if (nextBB != null) { 577 return nextBB.firstInstruction(); 578 } else { 579 return thisBB.lastInstruction(); 580 } 581 } 582 583 /** 584 * Helper function to generate the binary search tree for 585 * a lookupswitch bytecode 586 * 587 * @param switchInstr the lookupswitch instruction 588 * @param defaultBB the basic block of the default case 589 * @param ir the ir object 590 * @param curBlock the basic block to insert instructions into 591 * @param reg the RegisterOperand that contains the valued being switched on 592 * @param low the low index of cases (operands of switchInstr) 593 * @param high the high index of cases (operands of switchInstr) 594 * @param min 595 * @param max 596 * @return the last basic block created 597 */ 598 private static BasicBlock _lookupswitchHelper(Instruction switchInstr, RegisterOperand reg, 599 BasicBlock defaultBB, IR ir, BasicBlock curBlock, 600 int low, int high, int min, int max) { 601 if (VM.VerifyAssertions) { 602 VM._assert(low <= high, "broken control logic in _lookupswitchHelper"); 603 } 604 605 int middle = (low + high) >> 1; // find middle 606 607 // The following are used below to store the computed branch 608 // probabilities for the branches that are created to implement 609 // the binary search. Used only if basic block frequencies available 610 float lessProb = 0.0f; 611 float greaterProb = 0.0f; 612 float equalProb = 0.0f; 613 float sum = 0.0f; 614 615 // Sum the probabilities for all targets < middle 616 for (int i = low; i < middle; i++) { 617 lessProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability; 618 } 619 620 // Sum the probabilities for all targets > middle 621 for (int i = middle + 1; i <= high; i++) { 622 greaterProb += LookupSwitch.getBranchProfile(switchInstr, i).takenProbability; 623 } 624 equalProb = LookupSwitch.getBranchProfile(switchInstr, middle).takenProbability; 625 626 // The default case is a bit of a kludge. We know the total 627 // probability of executing the default case, but we have no 628 // idea which paths are taken to get there. For now, we'll 629 // assume that all paths that went to default were because the 630 // value was less than the smallest switch value. This ensures 631 // that all basic block appearing in the switch will have the 632 // correct weights (but the blocks in the binary switch 633 // generated may not). 634 if (low == 0) { 635 lessProb += LookupSwitch.getDefaultBranchProfile(switchInstr).takenProbability; 636 } 637 638 // Now normalize them so they are relative to the sum of the 639 // branches being considered in this piece of the subtree 640 sum = lessProb + equalProb + greaterProb; 641 if (sum > 0) { // check for divide by zero 642 lessProb /= sum; 643 equalProb /= sum; 644 greaterProb /= sum; 645 } 646 647 IntConstantOperand val = LookupSwitch.getClearMatch(switchInstr, middle); 648 int value = val.value; 649 BasicBlock greaterBlock = middle == high ? defaultBB : curBlock.createSubBlock(0, ir); 650 BasicBlock lesserBlock = low == middle ? defaultBB : curBlock.createSubBlock(0, ir); 651 // Generate this level of tests 652 BranchOperand branch = LookupSwitch.getClearTarget(switchInstr, middle); 653 BasicBlock branchBB = branch.target.getBasicBlock(); 654 curBlock.insertOut(branchBB); 655 if (low != high) { 656 if (value == min) { 657 curBlock.appendInstruction(IfCmp.create(INT_IFCMP, 658 ir.regpool.makeTempValidation(), 659 reg.copy(), 660 val, 661 ConditionOperand.EQUAL(), 662 branchBB.makeJumpTarget(), 663 new BranchProfileOperand(equalProb))); 664 } else { 665 666 // To compute the probability of the second compare, the first 667 // probability must be removed since the second branch is 668 // considered only if the first fails. 669 float secondIfProb = 0.0f; 670 sum = equalProb + greaterProb; 671 if (sum > 0) { 672 // if divide by zero, leave as is 673 secondIfProb = equalProb / sum; 674 } 675 676 curBlock.appendInstruction(IfCmp2.create(INT_IFCMP2, 677 ir.regpool.makeTempValidation(), 678 reg.copy(), 679 val, 680 ConditionOperand.LESS(), 681 lesserBlock.makeJumpTarget(), 682 new BranchProfileOperand(lessProb), 683 ConditionOperand.EQUAL(), 684 branchBB.makeJumpTarget(), 685 new BranchProfileOperand(secondIfProb))); 686 curBlock.insertOut(lesserBlock); 687 } 688 } else { // Base case: middle was the only case left to consider 689 if (min == max) { 690 curBlock.appendInstruction(Goto.create(GOTO, branch)); 691 curBlock.insertOut(branchBB); 692 } else { 693 curBlock.appendInstruction(IfCmp.create(INT_IFCMP, 694 ir.regpool.makeTempValidation(), 695 reg.copy(), 696 val, 697 ConditionOperand.EQUAL(), 698 branchBB.makeJumpTarget(), 699 new BranchProfileOperand(equalProb))); 700 BasicBlock newBlock = curBlock.createSubBlock(0, ir); 701 curBlock.insertOut(newBlock); 702 ir.cfg.linkInCodeOrder(curBlock, newBlock); 703 curBlock = newBlock; 704 curBlock.appendInstruction(defaultBB.makeGOTO()); 705 curBlock.insertOut(defaultBB); 706 } 707 } 708 // Generate sublevels as needed and splice together instr & bblist 709 if (middle < high) { 710 curBlock.insertOut(greaterBlock); 711 ir.cfg.linkInCodeOrder(curBlock, greaterBlock); 712 curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, greaterBlock, middle + 1, high, value + 1, max); 713 } 714 if (low < middle) { 715 ir.cfg.linkInCodeOrder(curBlock, lesserBlock); 716 curBlock = _lookupswitchHelper(switchInstr, reg, defaultBB, ir, lesserBlock, low, middle - 1, min, value - 1); 717 } 718 return curBlock; 719 } 720 721 /** 722 * Expand an array load. 723 * @param s the instruction to expand 724 * @param ir the containing IR 725 * @param op the load operator to use 726 * @param logwidth the log base 2 of the element type's size 727 */ 728 public static void doArrayLoad(Instruction s, IR ir, Operator op, int logwidth) { 729 if (LOWER_ARRAY_ACCESS) { 730 RegisterOperand result = ALoad.getClearResult(s); 731 Operand array = ALoad.getClearArray(s); 732 Operand index = ALoad.getClearIndex(s); 733 Operand offset; 734 LocationOperand loc = ALoad.getClearLocation(s); 735 if (index instanceof IntConstantOperand) { // constant propagation 736 offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth)); 737 } else { 738 if (logwidth != 0) { 739 offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth)); 740 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy()); 741 } else { 742 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index); 743 } 744 } 745 Load.mutate(s, op, result, array, offset, loc, ALoad.getClearGuard(s)); 746 } 747 } 748 749 /** 750 * Expand an array store. 751 * @param s the instruction to expand 752 * @param ir the containing IR 753 * @param op the store operator to use 754 * @param logwidth the log base 2 of the element type's size 755 */ 756 public static void doArrayStore(Instruction s, IR ir, Operator op, int logwidth) { 757 if (LOWER_ARRAY_ACCESS) { 758 Operand value = AStore.getClearValue(s); 759 Operand array = AStore.getClearArray(s); 760 Operand index = AStore.getClearIndex(s); 761 Operand offset; 762 LocationOperand loc = AStore.getClearLocation(s); 763 if (index instanceof IntConstantOperand) {// constant propagation 764 offset = AC(Address.fromIntZeroExtend(((IntConstantOperand) index).value << logwidth)); 765 } else { 766 if (logwidth != 0) { 767 offset = insertBinary(s, ir, INT_SHL, TypeReference.Int, index, IC(logwidth)); 768 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, offset.copy()); 769 } else { 770 offset = InsertUnary(s, ir, INT_2ADDRZerExt, TypeReference.Offset, index); 771 } 772 } 773 Store.mutate(s, op, value, array, offset, loc, AStore.getClearGuard(s)); 774 } 775 } 776 777 /** 778 * Helper method for call expansion. 779 * @param v the call instruction 780 * @param ir the containing IR 781 * @return the last expanded instruction 782 */ 783 static Instruction callHelper(Instruction v, IR ir) { 784 if (!Call.hasMethod(v)) { 785 if (VM.VerifyAssertions) VM._assert(Call.getAddress(v) instanceof RegisterOperand); 786 return v; // nothing to do....very low level call to address already in the register. 787 } 788 789 MethodOperand methOp = Call.getMethod(v); 790 791 // Handle recursive invocations. 792 if (methOp.hasPreciseTarget() && methOp.getTarget() == ir.method) { 793 Call.setAddress(v, new BranchOperand(ir.firstInstructionInCodeOrder())); 794 return v; 795 } 796 797 /* RRB 100500 */ 798 // generate direct call to specialized method if the method operand 799 // has been marked as a specialized call. 800 if (VM.runningVM) { 801 SpecializedMethod spMethod = methOp.spMethod; 802 if (spMethod != null) { 803 int smid = spMethod.getSpecializedMethodIndex(); 804 Call.setAddress(v, getSpecialMethod(v, ir, smid)); 805 return v; 806 } 807 } 808 809 // Used mainly (only?) by OSR 810 if (methOp.hasDesignatedTarget()) { 811 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, methOp.jtocOffset)); 812 return v; 813 } 814 815 if (methOp.isStatic()) { 816 if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v)); 817 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v))); 818 } else if (methOp.isVirtual()) { 819 if (VM.VerifyAssertions) VM._assert(Call.hasAddress(v)); 820 if (ir.options.H2L_CALL_VIA_JTOC && methOp.hasPreciseTarget()) { 821 // Call to precise type can go via JTOC 822 RVMMethod target = methOp.getTarget(); 823 Call.setAddress(v, 824 InsertLoadOffsetJTOC(v, 825 ir, 826 REF_LOAD, 827 TypeReference.CodeArray, 828 target.findOrCreateJtocOffset())); 829 } else { 830 Operand tib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy()); 831 Call.setAddress(v, 832 InsertLoadOffset(v, 833 ir, 834 REF_LOAD, 835 TypeReference.CodeArray, 836 tib, 837 Call.getClearAddress(v), 838 null, 839 TG())); 840 } 841 } else if (methOp.isSpecial()) { 842 RVMMethod target = methOp.getTarget(); 843 if (target == null || target.isObjectInitializer() || target.isStatic()) { 844 // target == null => we are calling an unresolved <init> method. 845 Call.setAddress(v, InsertLoadOffsetJTOC(v, ir, REF_LOAD, TypeReference.CodeArray, Call.getClearAddress(v))); 846 } else { 847 if (ir.options.H2L_CALL_VIA_JTOC) { 848 Call.setAddress(v, 849 InsertLoadOffsetJTOC(v, 850 ir, 851 REF_LOAD, 852 TypeReference.CodeArray, 853 target.findOrCreateJtocOffset())); 854 } else { 855 // invoking a virtual method; do it via TIB of target's declaring class. 856 Operand tib = getTIB(v, ir, target.getDeclaringClass()); 857 Call.setAddress(v, 858 InsertLoadOffset(v, 859 ir, 860 REF_LOAD, 861 TypeReference.CodeArray, 862 tib, 863 Call.getClearAddress(v), 864 null, 865 TG())); 866 } 867 } 868 } else { 869 if (VM.VerifyAssertions) VM._assert(methOp.isInterface()); 870 if (VM.VerifyAssertions) VM._assert(!Call.hasAddress(v)); 871 if (VM.BuildForIMTInterfaceInvocation) { 872 // SEE ALSO: FinalMIRExpansion (for hidden parameter) 873 Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy()); 874 InterfaceMethodSignature sig = InterfaceMethodSignature.findOrCreate(methOp.getMemberRef()); 875 Offset offset = sig.getIMTOffset(); 876 RegisterOperand address = null; 877 RegisterOperand IMT = 878 InsertLoadOffset(v, 879 ir, 880 REF_LOAD, 881 TypeReference.IMT, 882 RHStib.copy(), 883 Offset.fromIntZeroExtend(TIB_INTERFACE_DISPATCH_TABLE_INDEX << LOG_BYTES_IN_ADDRESS)); 884 address = InsertLoadOffset(v, ir, REF_LOAD, TypeReference.CodeArray, IMT.copyD2U(), offset); 885 886 Call.setAddress(v, address); 887 } else { 888 int itableIndex = -1; 889 if (VM.BuildForITableInterfaceInvocation && methOp.hasTarget()) { 890 RVMClass I = methOp.getTarget().getDeclaringClass(); 891 // search ITable variant 892 itableIndex = 893 InterfaceInvocation.getITableIndex(I, 894 methOp.getMemberRef().getName(), 895 methOp.getMemberRef().getDescriptor()); 896 } 897 if (itableIndex == -1) { 898 // itable index is not known at compile-time. 899 // call "invokeinterface" to resolve the object and method id 900 // into a method address 901 RegisterOperand realAddrReg = ir.regpool.makeTemp(TypeReference.CodeArray); 902 RVMMethod target = Entrypoints.invokeInterfaceMethod; 903 Instruction vp = 904 Call.create2(CALL, 905 realAddrReg, 906 AC(target.getOffset()), 907 MethodOperand.STATIC(target), 908 Call.getParam(v, 0).asRegister().copyU2U(), 909 IC(methOp.getMemberRef().getId())); 910 vp.position = v.position; 911 vp.bcIndex = RUNTIME_SERVICES_BCI; 912 v.insertBefore(vp); 913 callHelper(vp, ir); 914 Call.setAddress(v, realAddrReg.copyD2U()); 915 return v; 916 } else { 917 // itable index is known at compile-time. 918 // call "findITable" to resolve object + interface id into 919 // itable address 920 RegisterOperand iTable = ir.regpool.makeTemp(TypeReference.ITable); 921 Operand RHStib = getTIB(v, ir, Call.getParam(v, 0).copy(), Call.getGuard(v).copy()); 922 RVMMethod target = Entrypoints.findItableMethod; 923 Instruction fi = 924 Call.create2(CALL, 925 iTable, 926 AC(target.getOffset()), 927 MethodOperand.STATIC(target), 928 RHStib, 929 IC(methOp.getTarget().getDeclaringClass().getInterfaceId())); 930 fi.position = v.position; 931 fi.bcIndex = RUNTIME_SERVICES_BCI; 932 v.insertBefore(fi); 933 callHelper(fi, ir); 934 RegisterOperand address = 935 InsertLoadOffset(v, 936 ir, 937 REF_LOAD, 938 TypeReference.CodeArray, 939 iTable.copyD2U(), 940 Offset.fromIntZeroExtend(itableIndex << LOG_BYTES_IN_ADDRESS)); 941 Call.setAddress(v, address); 942 return v; 943 } 944 } 945 } 946 return v; 947 } 948 949 /** 950 * Generate the code to resolve a member (field/method) reference. 951 * @param s the RESOLVE_MEMBER instruction to expand 952 * @param ir the containing ir object 953 * @return the last expanded instruction 954 */ 955 private static Instruction resolveMember(Instruction s, IR ir) { 956 Operand memberOp = Unary.getClearVal(s); 957 RegisterOperand offset = Unary.getClearResult(s); 958 int dictId; 959 if (memberOp instanceof LocationOperand) { 960 dictId = ((LocationOperand) memberOp).getFieldRef().getId(); 961 } else { 962 dictId = ((MethodOperand) memberOp).getMemberRef().getId(); 963 } 964 965 BranchProfileOperand bp = BranchProfileOperand.never(); 966 BasicBlock predBB = s.getBasicBlock(); 967 BasicBlock succBB = predBB.splitNodeAt(s.prevInstructionInCodeOrder(), ir); 968 BasicBlock testBB = predBB.createSubBlock(s.bcIndex, ir, 1f - bp.takenProbability); 969 BasicBlock resolveBB = predBB.createSubBlock(s.bcIndex, ir, bp.takenProbability); 970 s.remove(); 971 972 // Get the offset from the appropriate RVMClassLoader array 973 // and check to see if it is valid 974 RegisterOperand offsetTable = getStatic(testBB.lastInstruction(), ir, Entrypoints.memberOffsetsField); 975 testBB.appendInstruction(Load.create(INT_LOAD, 976 offset.copyRO(), 977 offsetTable, 978 AC(Offset.fromIntZeroExtend(dictId << LOG_BYTES_IN_INT)), 979 new LocationOperand(TypeReference.Int), 980 TG())); 981 testBB.appendInstruction(Unary.create(INT_2ADDRSigExt, offset, offset.copy())); 982 testBB.appendInstruction(IfCmp.create(REF_IFCMP, 983 ir.regpool.makeTempValidation(), 984 offset.copy(), 985 AC(Address.fromIntSignExtend(NEEDS_DYNAMIC_LINK)), 986 ConditionOperand.EQUAL(), 987 resolveBB.makeJumpTarget(), 988 bp)); 989 990 // Handle the offset being invalid 991 resolveBB.appendInstruction(CacheOp.mutate(s, RESOLVE, memberOp)); 992 resolveBB.appendInstruction(testBB.makeGOTO()); 993 994 // Put together the CFG links & code order 995 predBB.insertOut(testBB); 996 ir.cfg.linkInCodeOrder(predBB, testBB); 997 testBB.insertOut(succBB); 998 testBB.insertOut(resolveBB); 999 ir.cfg.linkInCodeOrder(testBB, succBB); 1000 resolveBB.insertOut(testBB); // backedge 1001 ir.cfg.addLastInCodeOrder(resolveBB); // stick resolution code in outer space. 1002 return testBB.lastInstruction(); 1003 } 1004 1005 /** 1006 * Insert a binary instruction before s in the instruction stream. 1007 * @param s the instruction to insert before 1008 * @param ir the containing IR 1009 * @param operator the operator to insert 1010 * @param type the type of the result 1011 * @param o1 the first operand 1012 * @param o2 the second operand 1013 * @return the result operand of the inserted instruction 1014 */ 1015 public static RegisterOperand insertBinary(Instruction s, IR ir, Operator operator, 1016 TypeReference type, Operand o1, Operand o2) { 1017 RegisterOperand t = ir.regpool.makeTemp(type); 1018 s.insertBefore(CPOS(s, Binary.create(operator, t, o1, o2))); 1019 return t.copyD2U(); 1020 } 1021 1022 /** 1023 * Insert a unary instruction before s in the instruction stream. 1024 * @param s the instruction to insert before 1025 * @param ir the containing IR 1026 * @param operator the operator to insert 1027 * @param type the type of the result 1028 * @param o1 the operand 1029 * @return the result operand of the inserted instruction 1030 */ 1031 static RegisterOperand InsertUnary(Instruction s, IR ir, Operator operator, TypeReference type, 1032 Operand o1) { 1033 RegisterOperand t = ir.regpool.makeTemp(type); 1034 s.insertBefore(CPOS(s, Unary.create(operator, t, o1))); 1035 return t.copyD2U(); 1036 } 1037 1038 /** 1039 * Insert a guarded unary instruction before s in the instruction stream. 1040 * @param s the instruction to insert before 1041 * @param ir the containing IR 1042 * @param operator the operator to insert 1043 * @param type the type of the result 1044 * @param o1 the operand 1045 * @param guard the guard operand 1046 * @return the result operand of the inserted instruction 1047 */ 1048 static RegisterOperand InsertGuardedUnary(Instruction s, IR ir, Operator operator, 1049 TypeReference type, Operand o1, Operand guard) { 1050 RegisterOperand t = ir.regpool.makeTemp(type); 1051 s.insertBefore(GuardedUnary.create(operator, t, o1, guard)); 1052 return t.copyD2U(); 1053 } 1054 1055 /** 1056 * Insert a load off the JTOC before s in the instruction stream. 1057 * @param s the instruction to insert before 1058 * @param ir the containing IR 1059 * @param operator the operator to insert 1060 * @param type the type of the result 1061 * @param offset the offset to load at 1062 * @return the result operand of the inserted instruction 1063 */ 1064 static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator, 1065 TypeReference type, Offset offset) { 1066 return InsertLoadOffset(s, 1067 ir, 1068 operator, 1069 type, 1070 ir.regpool.makeJTOCOp(ir, s), 1071 AC(offset), 1072 new LocationOperand(offset), 1073 null); 1074 } 1075 1076 /** 1077 * Insert a load off the JTOC before s in the instruction stream. 1078 * @param s the instruction to insert before 1079 * @param ir the containing IR 1080 * @param operator the operator to insert 1081 * @param type the type of the result 1082 * @param offset the offset to load at 1083 * @return the result operand of the inserted instruction 1084 */ 1085 static RegisterOperand InsertLoadOffsetJTOC(Instruction s, IR ir, Operator operator, 1086 TypeReference type, Operand offset) { 1087 return InsertLoadOffset(s, ir, operator, type, ir.regpool.makeJTOCOp(ir, s), offset, null, null); 1088 } 1089 1090 /** 1091 * Insert a load off before s in the instruction stream. 1092 * @param s the instruction to insert before 1093 * @param ir the containing IR 1094 * @param operator the operator to insert 1095 * @param type the type of the result 1096 * @param reg2 the base to load from 1097 * @param offset the offset to load at 1098 * @return the result operand of the inserted instruction 1099 */ 1100 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator, 1101 TypeReference type, Operand reg2, Offset offset) { 1102 return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, null); 1103 } 1104 1105 /** 1106 * Insert a load off before s in the instruction stream. 1107 * @param s the instruction to insert before 1108 * @param ir the containing IR 1109 * @param operator the operator to insert 1110 * @param type the type of the result 1111 * @param reg2 the base to load from 1112 * @param offset the offset to load at 1113 * @param guard the guard operand 1114 * @return the result operand of the inserted instruction 1115 */ 1116 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator, 1117 TypeReference type, Operand reg2, Offset offset, 1118 Operand guard) { 1119 return InsertLoadOffset(s, ir, operator, type, reg2, offset, null, guard); 1120 } 1121 1122 /** 1123 * Insert a load off before s in the instruction stream. 1124 * @param s the instruction to insert before 1125 * @param ir the containing IR 1126 * @param operator the operator to insert 1127 * @param type the type of the result 1128 * @param reg2 the base to load from 1129 * @param offset the offset to load at 1130 * @param loc the location operand 1131 * @param guard the guard operand 1132 * @return the result operand of the inserted instruction 1133 */ 1134 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator, 1135 TypeReference type, Operand reg2, Offset offset, 1136 LocationOperand loc, Operand guard) { 1137 return InsertLoadOffset(s, ir, operator, type, reg2, AC(offset), loc, guard); 1138 } 1139 1140 /** 1141 * Insert a load off before s in the instruction stream. 1142 * @param s the instruction to insert before 1143 * @param ir the containing IR 1144 * @param operator the operator to insert 1145 * @param type the type of the result 1146 * @param reg2 the base to load from 1147 * @param offset the offset to load at 1148 * @param loc the location operand 1149 * @param guard the guard operand 1150 * @return the result operand of the inserted instruction 1151 */ 1152 static RegisterOperand InsertLoadOffset(Instruction s, IR ir, Operator operator, 1153 TypeReference type, Operand reg2, Operand offset, 1154 LocationOperand loc, Operand guard) { 1155 RegisterOperand regTarget = ir.regpool.makeTemp(type); 1156 Instruction s2 = Load.create(operator, regTarget, reg2, offset, loc, guard); 1157 s.insertBefore(s2); 1158 return regTarget.copyD2U(); 1159 } 1160 1161 /** get the tib from the object pointer to by obj */ 1162 static Operand getTIB(Instruction s, IR ir, Operand obj, Operand guard) { 1163 if (obj.isObjectConstant()) { 1164 // NB Constant types must already be resolved 1165 try { 1166 RVMType type = obj.getType().resolve(); 1167 return new TIBConstantOperand(type); 1168 } catch (NoClassDefFoundError e) { 1169 if (VM.runningVM) throw e; 1170 // Class not found during bootstrap due to chasing a class 1171 // only valid in the bootstrap JVM 1172 } 1173 } 1174 RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB); 1175 Instruction s2 = GuardedUnary.create(GET_OBJ_TIB, res, obj, guard); 1176 s.insertBefore(s2); 1177 return res.copyD2U(); 1178 } 1179 1180 /** get the class tib for type */ 1181 static Operand getTIB(Instruction s, IR ir, RVMType type) { 1182 return new TIBConstantOperand(type); 1183 //return getTIB(s, ir, new TypeOperand(type)); 1184 } 1185 1186 /** get the class tib for type */ 1187 static Operand getTIB(Instruction s, IR ir, TypeOperand type) { 1188 RVMType t = type.getVMType(); 1189 if (VM.BuildForIA32 && !MemoryManagerConstants.MOVES_TIBS && VM.runningVM && t != null && t.isResolved()) { 1190 Address addr = Magic.objectAsAddress(t.getTypeInformationBlock()); 1191 return new AddressConstantOperand(addr); 1192 } else if (!t.isResolved()) { 1193 RegisterOperand res = ir.regpool.makeTemp(TypeReference.TIB); 1194 s.insertBefore(Unary.create(GET_CLASS_TIB, res, type)); 1195 return res.copyD2U(); 1196 } else { 1197 return new TIBConstantOperand(t); 1198 } 1199 } 1200 1201 /** 1202 * Get an instance method from a TIB 1203 */ 1204 static RegisterOperand getInstanceMethod(Instruction s, IR ir, Operand tib, RVMMethod method) { 1205 return InsertLoadOffset(s, ir, REF_LOAD, TypeReference.CodeArray, tib, method.getOffset()); 1206 } 1207 1208 /** 1209 * Load an instance field. 1210 * @param s 1211 * @param ir 1212 * @param obj 1213 * @param field 1214 */ 1215 public static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field) { 1216 return getField(s, ir, obj, field, null); 1217 } 1218 1219 /** 1220 * Load an instance field. 1221 * @param s 1222 * @param ir 1223 * @param obj 1224 * @param field 1225 * @param guard 1226 */ 1227 static RegisterOperand getField(Instruction s, IR ir, RegisterOperand obj, RVMField field, 1228 Operand guard) { 1229 return InsertLoadOffset(s, 1230 ir, 1231 IRTools.getLoadOp(field.getType(), field.isStatic()), 1232 field.getType(), 1233 obj, 1234 field.getOffset(), 1235 new LocationOperand(field), 1236 guard); 1237 } 1238 1239 /* RRB 100500 */ 1240 /** 1241 * support for direct call to specialized method. 1242 */ 1243 static RegisterOperand getSpecialMethod(Instruction s, IR ir, int smid) { 1244 // First, get the pointer to the JTOC offset pointing to the 1245 // specialized Method table 1246 RegisterOperand reg = 1247 InsertLoadOffsetJTOC(s, 1248 ir, 1249 REF_LOAD, 1250 TypeReference.JavaLangObjectArray, 1251 AosEntrypoints.specializedMethodsField.getOffset()); 1252 RegisterOperand instr = 1253 InsertLoadOffset(s, 1254 ir, 1255 REF_LOAD, 1256 TypeReference.CodeArray, 1257 reg, 1258 Offset.fromIntZeroExtend(smid << LOG_BYTES_IN_INT)); 1259 return instr; 1260 } 1261 1262 /** 1263 * Expand symbolic SysCall target into a chain of loads from the bootrecord to 1264 * the desired target address. 1265 */ 1266 public static void expandSysCallTarget(Instruction s, IR ir) { 1267 MethodOperand sysM = Call.getMethod(s); 1268 if (sysM.getMemberRef().isFieldReference()) { 1269 RegisterOperand t1 = getStatic(s, ir, Entrypoints.the_boot_recordField); 1270 RVMField target = sysM.getMemberRef().asFieldReference().resolve(); 1271 Operand ip = getField(s, ir, t1, target); 1272 Call.setAddress(s, ip); 1273 } 1274 } 1275 1276 /** 1277 * Load a static field. 1278 * @param s 1279 * @param ir 1280 * @param field 1281 */ 1282 public static RegisterOperand getStatic(Instruction s, IR ir, RVMField field) { 1283 return InsertLoadOffsetJTOC(s, 1284 ir, 1285 IRTools.getLoadOp(field.getType(), field.isStatic()), 1286 field.getType(), 1287 field.getOffset()); 1288 } 1289 }