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